From d525a414978236682e067180a8a5d94189f67335 Mon Sep 17 00:00:00 2001 From: Ethan Mahintorabi Date: Tue, 15 Aug 2023 20:03:46 +0000 Subject: [PATCH 001/173] abc: Exposes dont_use flag in ABC ABC's read_lib command has a dont_use cell list that is configurable by the user. This PR exposes that option to Yosys. See https://github.com/berkeley-abc/abc/blob/5405d4787a86615de76afccf1356676fb5c56c1c/src/map/scl/scl.c#L285 for documentation on this option. Signed-off-by: Ethan Mahintorabi --- passes/techmap/abc.cc | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 364a8e54458..f36cadc8882 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -702,7 +702,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin 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) + const std::vector &cells, bool show_tempdir, bool sop_mode, bool abc_dress, std::vector &dont_use_cells) { module = current_module; map_autoidx = autoidx++; @@ -795,8 +795,13 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin std::string abc_script = stringf("read_blif \"%s/input.blif\"; ", tempdir_name.c_str()); if (!liberty_files.empty() || !genlib_files.empty()) { - for (std::string liberty_file : liberty_files) - abc_script += stringf("read_lib -w \"%s\"; ", liberty_file.c_str()); + std::string dont_use_args; + for (std::string dont_use_cell : dont_use_cells) { + dont_use_args += stringf("-X \"%s\" ", dont_use_cell.c_str()); + } + for (std::string liberty_file : liberty_files) { + abc_script += stringf("read_lib %s -w \"%s\" ; ", dont_use_args.c_str(), liberty_file.c_str()); + } for (std::string liberty_file : genlib_files) abc_script += stringf("read_library \"%s\"; ", liberty_file.c_str()); if (!constr_file.empty()) @@ -1503,6 +1508,10 @@ struct AbcPass : public Pass { log(" generate netlists for the specified cell library (using the liberty\n"); log(" file format).\n"); log("\n"); + log(" -dont_use \n"); + log(" generate netlists for the specified cell library (using the liberty\n"); + log(" file format).\n"); + log("\n"); log(" -genlib \n"); log(" generate netlists for the specified cell library (using the SIS Genlib\n"); log(" file format).\n"); @@ -1639,7 +1648,7 @@ struct AbcPass : public Pass { std::string exe_file = yosys_abc_executable; std::string script_file, default_liberty_file, constr_file, clk_str; - std::vector liberty_files, genlib_files; + 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; @@ -1722,6 +1731,10 @@ struct AbcPass : public Pass { liberty_files.push_back(args[++argidx]); continue; } + if (arg == "-dont_use" && argidx+1 < args.size()) { + dont_use_cells.push_back(args[++argidx]); + continue; + } if (arg == "-genlib" && argidx+1 < args.size()) { genlib_files.push_back(args[++argidx]); continue; @@ -2028,7 +2041,7 @@ struct AbcPass : public Pass { 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, - delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress); + delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress, dont_use_cells); continue; } @@ -2190,7 +2203,7 @@ struct AbcPass : public Pass { 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(), "$", - keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress); + 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); } } From 72bec94ef4f0ce8090f22c16cd5163b816e8c698 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 1 Sep 2023 10:15:51 +0200 Subject: [PATCH 002/173] Add missing file for XO3D --- techlibs/lattice/Makefile.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/techlibs/lattice/Makefile.inc b/techlibs/lattice/Makefile.inc index 4a908fa3ead..fd9ec2ed5e0 100644 --- a/techlibs/lattice/Makefile.inc +++ b/techlibs/lattice/Makefile.inc @@ -15,6 +15,7 @@ $(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_sim_xo3d.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_bb_ecp5.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_bb_xo2.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_bb_xo3.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_bb_xo3d.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/lutrams_map.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/lutrams.txt)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/brams_map_16kd.v)) From 73cb4977b2e493b840b23419919a63be7c83e6df Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 2 Sep 2023 00:14:04 +0000 Subject: [PATCH 003/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4f7f94cf167..960a31a01f3 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.32+74 +YOSYS_VER := 0.32+76 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 50d117956c7913d2bb661a948f0a1bff6bd0f3f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 4 Sep 2023 14:49:19 +0200 Subject: [PATCH 004/173] sim: Add print support --- passes/sat/sim.cc | 92 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 325e123201c..7b2236ad6fa 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -25,6 +25,7 @@ #include "kernel/ff.h" #include "kernel/yw.h" #include "kernel/json.h" +#include "kernel/fmt.h" #include @@ -168,11 +169,38 @@ struct SimInstance Const data; }; + struct print_state_t + { + Const past_trg; + Const past_en; + Const past_args; + + Cell *cell; + Fmt fmt; + + std::tuple _sort_label() const + { + return std::make_tuple( + cell->getParam(ID::TRG_ENABLE).as_bool(), // Group by trigger + cell->getPort(ID::TRG), + cell->getParam(ID::TRG_POLARITY), + -cell->getParam(ID::PRIORITY).as_int(), // Then sort by descending PRIORITY + cell + ); + } + + bool operator<(const print_state_t &other) const + { + return _sort_label() < other._sort_label(); + } + }; + dict ff_database; dict mem_database; pool formal_database; pool initstate_database; dict mem_cells; + std::vector print_database; std::vector memories; @@ -289,13 +317,26 @@ struct SimInstance if (shared->fst) fst_memories[name] = shared->fst->getMemoryHandles(scope + "." + RTLIL::unescape_id(name)); } - if (cell->type.in(ID($assert), ID($cover), ID($assume))) { + + if (cell->type.in(ID($assert), ID($cover), ID($assume))) formal_database.insert(cell); - } + if (cell->type == ID($initstate)) initstate_database.insert(cell); + + if (cell->type == ID($print)) { + print_database.emplace_back(); + auto &print = print_database.back(); + print.cell = cell; + print.fmt.parse_rtlil(cell); + print.past_trg = Const(State::Sx, cell->getPort(ID::TRG).size()); + print.past_args = Const(State::Sx, cell->getPort(ID::ARGS).size()); + print.past_en = State::Sx; + } } + std::sort(print_database.begin(), print_database.end()); + if (shared->zinit) { for (auto &it : ff_database) @@ -519,6 +560,9 @@ struct SimInstance return; } + if (cell->type == ID($print)) + return; + log_error("Unsupported cell type: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell)); } @@ -760,6 +804,50 @@ struct SimInstance } } + // Do prints *before* assertions + for (auto &print : print_database) { + Cell *cell = print.cell; + bool triggered = false; + + Const trg = get_state(cell->getPort(ID::TRG)); + Const en = get_state(cell->getPort(ID::EN)); + Const args = get_state(cell->getPort(ID::ARGS)); + + if (!en.as_bool()) + goto update_print; + + if (cell->getParam(ID::TRG_ENABLE).as_bool()) { + Const trg_pol = cell->getParam(ID::TRG_POLARITY); + for (int i = 0; i < trg.size(); i++) { + bool pol = trg_pol[i] == State::S1; + State curr = trg[i], past = print.past_trg[i]; + if (pol && curr == State::S1 && past == State::S0) + triggered = true; + if (!pol && curr == State::S0 && past == State::S1) + triggered = true; + } + } else { + if (args != print.past_args || en != print.past_en) + triggered = true; + } + + if (triggered) { + int pos = 0; + for (auto &part : print.fmt.parts) { + part.sig = args.extract(pos, part.sig.size()); + pos += part.sig.size(); + } + + std::string rendered = print.fmt.render(); + log("%s", rendered.c_str()); + } + + update_print: + print.past_trg = trg; + print.past_en = en; + print.past_args = args; + } + if (check_assertions) { for (auto cell : formal_database) From 3de84b959f2d77244d1a5d8a18aac4d8c67a8de8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 4 Sep 2023 14:48:49 +0200 Subject: [PATCH 005/173] memory_libmap: Tweak whitespace --- passes/memory/memory_libmap.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/memory/memory_libmap.cc b/passes/memory/memory_libmap.cc index 6e5a806fd0e..f8b0eec1d8d 100644 --- a/passes/memory/memory_libmap.cc +++ b/passes/memory/memory_libmap.cc @@ -667,7 +667,7 @@ void MemMapping::assign_wr_ports() { if (used >= GetSize(pg.names)) { log_reject(*cfg.def, pg, "not enough unassigned ports remaining"); continue; - } + } for (int pvi = 0; pvi < GetSize(pg.variants); pvi++) { auto &def = pg.variants[pvi]; // Make sure the target is a write port. @@ -2114,7 +2114,7 @@ struct MemoryLibMapPass : public Pass { log(" memory_libmap -lib [-D ] [selection]\n"); log("\n"); log("This pass takes a description of available RAM cell types and maps\n"); - log("all selected memories to one of them, or leaves them to be mapped to FFs.\n"); + log("all selected memories to one of them, or leaves them to be mapped to FFs.\n"); log("\n"); log(" -lib \n"); log(" Selects a library file containing RAM cell definitions. This option\n"); From c6566b660f8343be882cbb4fadedfa823f48e7f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 4 Sep 2023 14:49:01 +0200 Subject: [PATCH 006/173] memlib.md: Fix typo --- passes/memory/memlib.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/memory/memlib.md b/passes/memory/memlib.md index fdc2d4bed27..855aa1345fb 100644 --- a/passes/memory/memlib.md +++ b/passes/memory/memlib.md @@ -267,7 +267,7 @@ The address is always `abits` wide. If a non-narrowest width is used, the appro bits will be tied to 0. -### Port `width` prooperty +### Port `width` property If the RAM has `per_port` widths, the available width selection can be further described on per-port basis, by using one of the following properties: From b75959f1f25573d8c67436e748223290a3645074 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 00:14:21 +0000 Subject: [PATCH 007/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 960a31a01f3..492ea14832c 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.32+76 +YOSYS_VER := 0.32+79 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 2584903a0605cc7ffdfc1996254ccc1f548403f2 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 5 Sep 2023 08:08:51 +0200 Subject: [PATCH 008/173] Release version 0.33 --- CHANGELOG | 12 +++++++++++- Makefile | 4 ++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 027187b6d9f..f388705ccf3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,8 +2,18 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.32 .. Yosys 0.33-dev +Yosys 0.32 .. Yosys 0.33 -------------------------- + * Various + - Added "$print" cell, produced by "$display" and "$write" + Verilog tasks. + - Added "$print" cell handling in CXXRTL. + + * Lattice FPGA support + - Added generic "synth_lattice" pass (for now MachXO2/XO3/XO3D) + - Removed "synth_machxo2" pass + - Pass "ecp5_gsr" renamed to "lattice_gsr" + - "synth_machxo2" equivalent is "synth_lattice -family xo2" Yosys 0.31 .. Yosys 0.32 -------------------------- diff --git a/Makefile b/Makefile index 492ea14832c..c7a9ed6b63a 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.32+79 +YOSYS_VER := 0.33 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -157,7 +157,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline fbab08a.. | wc -l`/;" Makefile +# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline fbab08a.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # From 11a2de815ae6e799dd37c4d220255042f1bd5608 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 5 Sep 2023 08:11:03 +0200 Subject: [PATCH 009/173] Next dev cycle --- CHANGELOG | 3 +++ Makefile | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f388705ccf3..465918a36d8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,9 @@ List of major changes and improvements between releases ======================================================= +Yosys 0.33 .. Yosys 0.34-dev +-------------------------- + Yosys 0.32 .. Yosys 0.33 -------------------------- * Various diff --git a/Makefile b/Makefile index c7a9ed6b63a..fa95b7b7035 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33 +YOSYS_VER := 0.33+0 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -157,7 +157,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: -# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline fbab08a.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 2584903.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # From e995dddeaaa4bcdefdeebb082e1f1a8215d467bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 16 Aug 2023 12:42:00 +0200 Subject: [PATCH 010/173] abc: Warn about replacing undef bits --- passes/techmap/abc.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 364a8e54458..b2d5c5e36f3 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -127,10 +127,15 @@ bool clk_polarity, en_polarity, arst_polarity, srst_polarity; RTLIL::SigSpec clk_sig, en_sig, arst_sig, srst_sig; dict pi_map, po_map; +int undef_bits_lost; + 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) { assign_map.apply(bit); + if (bit == State::Sx) + undef_bits_lost++; + if (signal_map.count(bit) == 0) { gate_t gate; gate.id = signal_list.size(); @@ -880,10 +885,15 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin } } + undef_bits_lost = 0; + had_init = false; for (auto c : cells) extract_cell(c, 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); From d4d951657fbf273d58070076009453d541361f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 4 Sep 2023 14:55:11 +0200 Subject: [PATCH 011/173] sim: Add `-assert` option to fail on failed assertions --- passes/sat/sim.cc | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 325e123201c..e04fa564235 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -109,6 +109,7 @@ struct SimShared int next_output_id = 0; int step = 0; std::vector triggered_assertions; + bool serious_asserts = false; }; void zinit(State &v) @@ -781,8 +782,12 @@ struct SimInstance if (cell->type == ID($assume) && en == State::S1 && a != State::S1) log("Assumption %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str()); - if (cell->type == ID($assert) && en == State::S1 && a != State::S1) - log_warning("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str()); + if (cell->type == ID($assert) && en == State::S1 && a != State::S1) { + if (shared->serious_asserts) + log_error("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str()); + else + log_warning("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str()); + } } } @@ -2497,6 +2502,10 @@ struct SimPass : public Pass { log(" -sim-gate\n"); log(" co-simulation, x in FST can match any value in simulation\n"); log("\n"); + log(" -assert\n"); + log(" fail the simulation command if, in the course of simulating,\n"); + log(" any of the asserts in the design fail\n"); + log("\n"); log(" -q\n"); log(" disable per-cycle/sample log message\n"); log("\n"); @@ -2651,6 +2660,10 @@ struct SimPass : public Pass { worker.sim_mode = SimulationMode::gate; continue; } + if (args[argidx] == "-assert") { + worker.serious_asserts = true; + continue; + } if (args[argidx] == "-x") { worker.ignore_x = true; continue; From 2d0fc040cfe4413e3b2c8209b4b5a23b5866374b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 5 Sep 2023 21:40:24 +0200 Subject: [PATCH 012/173] ast: Substitute rvalues when parsing out print arguments Apply the local substitutions stemming from process context when parsing out format arguments to `$display` or other statements. --- frontends/ast/genrtlil.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 81fb3189d94..d62f06ae549 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -759,7 +759,7 @@ struct AST_INTERNAL::ProcessGenerator arg.realtime = true; } else { arg.type = VerilogFmtArg::INTEGER; - arg.sig = node->genRTLIL(); + arg.sig = node->genWidthRTLIL(-1, false, &subst_rvalue_map.stdmap()); arg.signed_ = is_signed; } args.push_back(arg); From 83b1a57eed27604fa1a45193ee6894a5e0764971 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 6 Sep 2023 00:14:34 +0000 Subject: [PATCH 013/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fa95b7b7035..907891db33f 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+0 +YOSYS_VER := 0.33+3 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 4edb1a19210b9b3118d7b0072e13a4363f81fb94 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Tue, 5 Sep 2023 22:19:28 -0400 Subject: [PATCH 014/173] sv: support assignments within expressions - Add support for assignments within expressions, e.g., `x[y++] = z;` or `x = (y *= 2) - 1;`. The logic is handled entirely within the parser by injecting statements into the current procedural block. - Add support for pre-increment/decrement statements, which are behaviorally equivalent to post-increment/decrement statements. - Fix non-standard attribute position used for post-increment/decrement statements. --- CHANGELOG | 4 + README.md | 2 + frontends/verilog/verilog_parser.y | 113 ++++++++++++++++++++------ tests/verilog/asgn_expr.sv | 60 ++++++++++++++ tests/verilog/asgn_expr.ys | 3 + tests/verilog/asgn_expr_not_proc_1.ys | 7 ++ tests/verilog/asgn_expr_not_proc_2.ys | 7 ++ tests/verilog/asgn_expr_not_proc_3.ys | 7 ++ tests/verilog/asgn_expr_not_proc_4.ys | 7 ++ tests/verilog/asgn_expr_not_proc_5.ys | 7 ++ tests/verilog/asgn_expr_not_sv_1.ys | 7 ++ tests/verilog/asgn_expr_not_sv_2.ys | 7 ++ tests/verilog/asgn_expr_not_sv_3.ys | 7 ++ tests/verilog/asgn_expr_not_sv_4.ys | 15 ++++ tests/verilog/task_attr.ys | 2 +- 15 files changed, 231 insertions(+), 24 deletions(-) create mode 100644 tests/verilog/asgn_expr.sv create mode 100644 tests/verilog/asgn_expr.ys create mode 100644 tests/verilog/asgn_expr_not_proc_1.ys create mode 100644 tests/verilog/asgn_expr_not_proc_2.ys create mode 100644 tests/verilog/asgn_expr_not_proc_3.ys create mode 100644 tests/verilog/asgn_expr_not_proc_4.ys create mode 100644 tests/verilog/asgn_expr_not_proc_5.ys create mode 100644 tests/verilog/asgn_expr_not_sv_1.ys create mode 100644 tests/verilog/asgn_expr_not_sv_2.ys create mode 100644 tests/verilog/asgn_expr_not_sv_3.ys create mode 100644 tests/verilog/asgn_expr_not_sv_4.ys diff --git a/CHANGELOG b/CHANGELOG index 465918a36d8..a662ba4dad3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,10 @@ List of major changes and improvements between releases Yosys 0.33 .. Yosys 0.34-dev -------------------------- + * SystemVerilog + - Added support for assignments within expressions, e.g., `x[y++] = z;` or + `x = (y *= 2) - 1;`. + Yosys 0.32 .. Yosys 0.33 -------------------------- * Various diff --git a/README.md b/README.md index 5e5a8ec3e12..69a227b7fb5 100644 --- a/README.md +++ b/README.md @@ -592,6 +592,8 @@ from SystemVerilog: - SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether ports are inputs or outputs are supported. +- Assignments within expressions are supported. + Building the documentation ========================== diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 1e82940bbbd..d901b3b558d 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -292,6 +292,61 @@ static void rewriteGenForDeclInit(AstNode *loop) substitute(incr); } +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(AstNode *lhs, dict *attr, AST::AstNodeType op, YYLTYPE begin, YYLTYPE end) +{ + AstNode *one = AstNode::mkconst_int(1, true); + AstNode *rhs = new AstNode(op, lhs->clone(), one); + AstNode *stmt = new AstNode(AST_ASSIGN_EQ, lhs, rhs); + SET_AST_NODE_LOC(stmt, begin, end); + if (attr != nullptr) + append_attr(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(lhs, attr, op, begin, end); + log_assert(stmt->type == AST_ASSIGN_EQ); + AstNode *expr = stmt->children[0]->clone(); + if (undo) { + AstNode *minus_one = AstNode::mkconst_int(-1, true); + expr = new AstNode(op, expr, minus_one); + } + SET_AST_NODE_LOC(expr, begin, end); + return expr; +} + +// 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} @@ -358,7 +413,7 @@ static void rewriteGenForDeclInit(AstNode *loop) %type integer_atom_type integer_vector_type %type attr case_attr %type struct_union -%type asgn_binop +%type asgn_binop inc_or_dec_op %type genvar_identifier %type specify_target @@ -2610,17 +2665,15 @@ simple_behavioral_stmt: SET_AST_NODE_LOC(node, @2, @5); append_attr(node, $1); } | - attr lvalue TOK_INCREMENT { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, new AstNode(AST_ADD, $2->clone(), AstNode::mkconst_int(1, true))); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @2, @3); - append_attr(node, $1); + attr lvalue attr inc_or_dec_op { + // The position 1 attr to avoid shift/reduce conflicts with the + // other productions. We reject attributes in that position. + if (!$1->empty()) + frontend_verilog_yyerror("Attributes are not allowed on this size of the lvalue in an inc_or_dec_expression!"); + addIncOrDecStmt($2, $3, $4, @1, @4); } | - attr lvalue TOK_DECREMENT { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, new AstNode(AST_SUB, $2->clone(), AstNode::mkconst_int(1, true))); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @2, @3); - append_attr(node, $1); + inc_or_dec_op attr lvalue { + addIncOrDecStmt($3, $2, $1, @1, @3); } | attr lvalue OP_LE delay expr { AstNode *node = new AstNode(AST_ASSIGN_LE, $2, $5); @@ -2629,18 +2682,7 @@ simple_behavioral_stmt: append_attr(node, $1); } | attr lvalue asgn_binop delay expr { - AstNode *expr_node = $5; - if ($3 == AST_SHIFT_LEFT || $3 == AST_SHIFT_RIGHT || - $3 == AST_SHIFT_SLEFT || $3 == AST_SHIFT_SRIGHT) { - expr_node = new AstNode(AST_TO_UNSIGNED, expr_node); - SET_AST_NODE_LOC(expr_node, @5, @5); - } - AstNode *op_node = new AstNode($3, $2->clone(), expr_node); - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, op_node); - SET_AST_NODE_LOC(op_node, @2, @5); - SET_AST_NODE_LOC(node, @2, @5); - ast_stack.back()->children.push_back(node); - append_attr(node, $1); + addAsgnBinopStmt($1, $2, $3, $5, @2, @5); }; asgn_binop: @@ -2657,6 +2699,12 @@ asgn_binop: TOK_SSHL_ASSIGN { $$ = AST_SHIFT_SLEFT; } | TOK_SSHR_ASSIGN { $$ = AST_SHIFT_SRIGHT; } ; +inc_or_dec_op: + // NOTE: These should only be permitted in SV mode, but Yosys has + // allowed them in all modes since support for them was added in 2017. + TOK_INCREMENT { $$ = AST_ADD; } | + TOK_DECREMENT { $$ = AST_SUB; } ; + for_initialization: TOK_ID '=' expr { AstNode *ident = new AstNode(AST_IDENTIFIER); @@ -3149,6 +3197,14 @@ expr: $$->children.push_back($6); SET_AST_NODE_LOC($$, @1, @$); append_attr($$, $3); + } | + inc_or_dec_op attr rvalue { + $$ = addIncOrDecExpr($3, $2, $1, @1, @3, false); + } | + // 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); }; basic_expr: @@ -3436,6 +3492,17 @@ basic_expr: frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); $$ = new AstNode(AST_CAST_SIZE, $1, $4); SET_AST_NODE_LOC($$, @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); + $$ = $2->clone(); + } | + '(' expr asgn_binop expr ')' { + ensureAsgnExprAllowed(); + $$ = addAsgnBinopStmt(nullptr, $2, $3, $4, @2, @4)-> clone(); }; concat_list: diff --git a/tests/verilog/asgn_expr.sv b/tests/verilog/asgn_expr.sv new file mode 100644 index 00000000000..567034d107d --- /dev/null +++ b/tests/verilog/asgn_expr.sv @@ -0,0 +1,60 @@ +module top; + integer x, y, z; + task check; + input integer a, b, c; + assert (x == a); + assert (y == b); + assert (z == c); + endtask + always_comb begin + x = 0; y = 0; z = 0; + check(0, 0, 0); + + // post-increment/decrement statements + x++; + check(1, 0, 0); + y (* foo *) ++; + check(1, 1, 0); + z--; + check(1, 1, -1); + z (* foo *) --; + check(1, 1, -2); + + // pre-increment/decrement statements are equivalent + ++z; + check(1, 1, -1); + ++ (* foo *) z; + check(1, 1, 0); + --x; + check(0, 1, 0); + -- (* foo *) y; + check(0, 0, 0); + + // procedural pre-increment/decrement expressions + z = ++x; + check(1, 0, 1); + z = ++ (* foo *) x; + check(2, 0, 2); + y = --x; + check(1, 1, 2); + y = -- (* foo *) x; + + // procedural post-increment/decrement expressions + // TODO: support attributes on post-increment/decrement + check(0, 0, 2); + y = x++; + check(1, 0, 2); + y = x--; + check(0, 1, 2); + + // procedural assignment expressions + x = (y = (z = 99) + 1) + 1; + check(101, 100, 99); + x = (y *= 2); + check(200, 200, 99); + x = (z >>= 2) * 4; + check(96, 200, 24); + y = (z >>= 1'sb1) * 2; // shift is implicitly cast to unsigned + check(96, 24, 12); + end +endmodule diff --git a/tests/verilog/asgn_expr.ys b/tests/verilog/asgn_expr.ys new file mode 100644 index 00000000000..18180c7854f --- /dev/null +++ b/tests/verilog/asgn_expr.ys @@ -0,0 +1,3 @@ +read_verilog -sv asgn_expr.sv +proc +sat -verify -prove-asserts -show-all diff --git a/tests/verilog/asgn_expr_not_proc_1.ys b/tests/verilog/asgn_expr_not_proc_1.ys new file mode 100644 index 00000000000..72ba0bd89dc --- /dev/null +++ b/tests/verilog/asgn_expr_not_proc_1.ys @@ -0,0 +1,7 @@ +logger -expect error "Assignments within expressions are only permitted within procedures." 1 +read_verilog -sv < Date: Wed, 6 Sep 2023 19:25:47 +0200 Subject: [PATCH 015/173] xprop: Fix polarity errors and generate hdlnames * Fixes a non-deterministic polarity error for $eqx/$nex cells * Fixes a deterministic polarity error for $_NOR_ and $_ORNOT_ cells * Generates hdlnames when xprop is run after flatten --- passes/cmds/xprop.cc | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/passes/cmds/xprop.cc b/passes/cmds/xprop.cc index 5e78ff9fce4..310d6d773d5 100644 --- a/passes/cmds/xprop.cc +++ b/passes/cmds/xprop.cc @@ -493,8 +493,9 @@ struct XpropWorker auto sig_b = cell->getPort(ID::B); auto name = cell->name; + auto type = cell->type; module->remove(cell); - if (cell->type == ID($eqx)) + if (type == ID($eqx)) module->addEq(name, sig_a, sig_b, sig_y); else module->addNe(name, sig_a, sig_b, sig_y); @@ -534,7 +535,7 @@ struct XpropWorker auto enc_b = encoded(sig_b); auto enc_y = encoded(sig_y, true); - if (cell->type.in(ID($or), ID($_OR_))) + if (cell->type.in(ID($or), ID($_OR_), ID($_NOR_), ID($_ORNOT_))) enc_a.invert(), enc_b.invert(), enc_y.invert(); if (cell->type.in(ID($_NAND_), ID($_NOR_))) enc_y.invert(); @@ -1027,12 +1028,25 @@ struct XpropWorker for (auto wire : module->selected_wires()) { if (wire->port_input || wire->port_output || !wire->name.isPublic()) continue; - auto name_d = module->uniquify(stringf("%s_d", wire->name.c_str())); - auto name_x = module->uniquify(stringf("%s_x", wire->name.c_str())); + int index_d = 0; + int index_x = 0; + auto name_d = module->uniquify(stringf("%s_d", wire->name.c_str()), index_d); + auto name_x = module->uniquify(stringf("%s_x", wire->name.c_str()), index_x); + + auto hdlname = wire->get_hdlname_attribute(); auto wire_d = module->addWire(name_d, GetSize(wire)); auto wire_x = module->addWire(name_x, GetSize(wire)); + if (!hdlname.empty()) { + auto hdlname_d = hdlname; + auto hdlname_x = hdlname; + hdlname_d.back() += index_d ? stringf("_d_%d", index_d) : "_d"; + hdlname_x.back() += index_x ? stringf("_x_%d", index_x) : "_x"; + wire_d->set_hdlname_attribute(hdlname_d); + wire_x->set_hdlname_attribute(hdlname_x); + } + auto enc = encoded(wire); module->connect(wire_d, enc.is_1); module->connect(wire_x, enc.is_x); From fedefa26bccaf023fdf4ee82d51fe63ecdbf6191 Mon Sep 17 00:00:00 2001 From: andyfox-rushc Date: Wed, 6 Sep 2023 16:35:17 -0700 Subject: [PATCH 016/173] multpass -- create Booth Encoded multipliers for --- passes/techmap/Makefile.inc | 1 + passes/techmap/multpass.cc | 1541 +++++++++++++++++++++++++++++++++++ 2 files changed, 1542 insertions(+) create mode 100644 passes/techmap/multpass.cc diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 1b834fabc3b..8b0b2aa23b7 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -4,6 +4,7 @@ OBJS += passes/techmap/techmap.o OBJS += passes/techmap/simplemap.o OBJS += passes/techmap/dfflibmap.o OBJS += passes/techmap/maccmap.o +OBJS += passes/techmap/multpass.o OBJS += passes/techmap/libparse.o ifeq ($(ENABLE_ABC),1) diff --git a/passes/techmap/multpass.cc b/passes/techmap/multpass.cc new file mode 100644 index 00000000000..e55a0441448 --- /dev/null +++ b/passes/techmap/multpass.cc @@ -0,0 +1,1541 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * + * 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. + * + */ + +/* + MultPass + -------- + + Replace $mul with booth encoded multipliers. Two different + architectures used for signed/unsigned. + + References: + Signed architecture: A Low Power Radix-4 Booth Multipliers with Pre-Encoded Mechanism, IEEE Access + https://ieeexplore.ieee.org/document/9121226 + + Unsigned architecture: Gary Bewick, Fast Multiplication algorithms and implementation. Stanford PhD: + http://i.stanford.edu/pub/cstr/reports/csl/tr/94/617/CSL-TR-94-617.pdf + + How to use: + Add multpass to your yosys script eg: + + read_verilog smultiply5_rtl.v + opt + wreduce + opt + multpass + alumacc + maccmap + opt + techmap -map ./techmap.v + dfflibmap -liberty NangateOpenCellLibrary_typical.lib + abc -liberty NangateOpenCellLibrary_typical.lib + stat -liberty NangateOpenCellLibrary_typical.lib + write_verilog -norename booth_final.v +*/ + +#include "kernel/sigtools.h" +#include "kernel/yosys.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct MultPassWorker { + + RTLIL::Module *module; + SigMap sigmap; + int booth_counter; + + MultPassWorker(RTLIL::Module *module) : module(module), sigmap(module) { booth_counter = 0; } + + // Helper routines for building architecture subcomponents + + void connect_sigSpecToWire(RTLIL::Wire *ip, const SigSpec &v) + { + auto g = module->addCell(NEW_ID, ID($pos)); + g->setParam(ID::A_WIDTH, 1); + g->setParam(ID::Y_WIDTH, 1); + g->setParam(ID::A_SIGNED, false); + g->setPort(ID::A, ip); + g->setPort(ID::Y, v); + } + + RTLIL::Wire *mk_wireFromSigSpec(const SigSpec &v) + { + + auto g = module->addCell(NEW_ID, ID($pos)); + Wire *ret = module->addWire(NEW_ID, 1); + g->setPort(ID::A, v); + g->setPort(ID::Y, ret); + g->setParam(ID::A_WIDTH, 1); + g->setParam(ID::Y_WIDTH, 1); + g->setParam(ID::A_SIGNED, false); + return ret; + } + + // fuse wires. + void join_wires_with_buffer(RTLIL::Wire *ip, RTLIL::Wire *op) + { + std::string wire_name = "join_"; + auto g = module->addCell(new_id(wire_name, __LINE__, ""), ID($pos)); + g->setParam(ID::A_WIDTH, 1); + g->setParam(ID::Y_WIDTH, 1); + g->setParam(ID::A_SIGNED, false); + g->setPort(ID::A, ip); + g->setPort(ID::Y, op); + } + + // Unary gate + RTLIL::Wire *mk_ugate1(const RTLIL::IdString &red_typ, std::string &name, RTLIL::Wire *ip1, std::string &op_name) + { + std::string op_wire_name; + if (op_name.empty()) + op_wire_name = name + "_o"; + else + op_wire_name = op_name; + RTLIL::Wire *ret = module->addWire(new_id(op_wire_name, __LINE__, ""), 1); + auto g = module->addCell(new_id(name, __LINE__, ""), red_typ); + g->setPort(ID::A, ip1); + g->setPort(ID::Y, ret); + g->setParam(ID::A_SIGNED, false); + g->setParam(ID::A_WIDTH, 1); + g->setParam(ID::Y_WIDTH, 1); + return ret; + } + + // Binary gate + RTLIL::Wire *mk_ugate2(const RTLIL::IdString &red_typ, std::string &name, RTLIL::Wire *ip1, RTLIL::Wire *ip2, std::string &op_name) + { + auto g = module->addCell(new_id(name, __LINE__, ""), red_typ); + std::string op_wire_name; + if (op_name.empty()) + op_wire_name = name + "_o"; + else + op_wire_name = op_name; + + auto ret = module->addWire(new_id(op_wire_name, __LINE__, ""), 1); + + g->setPort(ID::A, ip1); + g->setPort(ID::B, ip2); + g->setPort(ID::Y, ret); + g->setParam(ID::A_SIGNED, false); + g->setParam(ID::B_SIGNED, false); + g->setParam(ID::A_WIDTH, 1); + g->setParam(ID::B_WIDTH, 1); + g->setParam(ID::Y_WIDTH, 1); + return ret; + } + + // Booth unsigned decoder lsb + void BuildBur4d_lsb(std::string &name, RTLIL::Wire *lsb_i, RTLIL::Wire *one_i, RTLIL::Wire *s_i, RTLIL::Wire *&ppij_o, + std::string op_wire_name) + { + std::string empty; + auto and_op = mk_ugate2(ID($and), name, lsb_i, one_i, empty); + ppij_o = mk_ugate2(ID($xor), name, and_op, s_i, op_wire_name); + } + + // Booth unsigned radix4 decoder + void BuildBur4d_n(std::string &name, RTLIL::Wire *yn_i, RTLIL::Wire *ynm1_i, RTLIL::Wire *one_i, RTLIL::Wire *two_i, RTLIL::Wire *s_i, + RTLIL::Wire *&ppij_o) + { + // ppij = ((yn & one) | (ynm1 & two)) ^ s; + std::string empty; + auto an1 = mk_ugate2(ID($and), name, yn_i, one_i, empty); + auto an2 = mk_ugate2(ID($and), name, ynm1_i, two_i, empty); + auto or1 = mk_ugate2(ID($or), name, an1, an2, empty); + ppij_o = mk_ugate2(ID($xor), name, s_i, or1, empty); + } + + // Booth unsigned radix4 decoder + void BuildBur4d_msb(std::string &name, RTLIL::Wire *msb_i, RTLIL::Wire *two_i, RTLIL::Wire *s_i, RTLIL::Wire *&ppij_o) + { + // ppij = (msb & two) ^ s; + std::string empty; + auto an1 = mk_ugate2(ID($and), name, msb_i, two_i, empty); + ppij_o = mk_ugate2(ID($xor), name, s_i, an1, empty); + } + + // half adder, used in CPA + void BuildHa(std::string &name, RTLIL::Wire *a_i, RTLIL::Wire *b_i, RTLIL::Wire *&s_o, RTLIL::Wire *&c_o) + { + std::string empty; + s_o = mk_ugate2(ID($xor), name, a_i, b_i, empty); + c_o = mk_ugate2(ID($and), name, a_i, b_i, empty); + } + + // Booth unsigned radix 4 encoder + void BuildBur4e(std::string &name, RTLIL::Wire *y0_i, RTLIL::Wire *y1_i, RTLIL::Wire *y2_i, + + RTLIL::Wire *&one_o, RTLIL::Wire *&two_o, RTLIL::Wire *&s_o, RTLIL::Wire *&sb_o) + { + + std::string empty; + one_o = mk_ugate2(ID($xor), name, y0_i, y1_i, empty); + s_o = y2_i; + sb_o = mk_ugate1(ID($not), name, y2_i, empty); + auto inv_y1_xor_y2 = mk_ugate1(ID($not), name, mk_ugate2(ID($xor), name, y1_i, y2_i, empty), empty); + two_o = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, inv_y1_xor_y2, one_o, empty), empty); + } + + void BuildBr4e(std::string &name, RTLIL::Wire *y2_m1_i, + RTLIL::Wire *y2_i, // y2i + RTLIL::Wire *y2_p1_i, + + RTLIL::Wire *&negi_o, RTLIL::Wire *&twoi_n_o, RTLIL::Wire *&onei_n_o, RTLIL::Wire *&cori_o) + { + + std::string empty; + auto y2_p1_n = mk_ugate1(ID($not), name, y2_p1_i, empty); + auto y2_n = mk_ugate1(ID($not), name, y2_i, empty); + auto y2_m1_n = mk_ugate1(ID($not), name, y2_m1_i, empty); + + // negi_o = y2_p1_i + negi_o = mk_ugate1(ID($pos), name, y2_p1_i, empty); + // twoi_n = ~( + // (y2_p1_n & y2_i & y2_m1_i) | + // (y2_p1 & y2_n & y2_m1_n) + // ) + auto and3_1 = mk_ugate2(ID($and), name, y2_p1_n, mk_ugate2(ID($and), name, y2_i, y2_m1_i, empty), empty); + auto and3_2 = mk_ugate2(ID($and), name, y2_p1_i, mk_ugate2(ID($and), name, y2_n, y2_m1_n, empty), empty); + + twoi_n_o = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, and3_1, and3_2, empty), empty); + // onei_n = ~(y2_m1_i ^ y2_i); + onei_n_o = mk_ugate1(ID($not), name, mk_ugate2(ID($xor), name, y2_m1_i, y2_i, empty), empty); + // cori = (y2_m1_n | y2_n) & y2_p1_i; + cori_o = mk_ugate2(ID($and), name, y2_p1_i, mk_ugate2(ID($or), name, y2_m1_n, y2_n, empty), empty); + } + + // + // signed booth radix 4 decoder + // + void BuildBr4d(std::string &name, RTLIL::Wire *nxj_m1_i, RTLIL::Wire *twoi_n_i, RTLIL::Wire *xj_i, RTLIL::Wire *negi_i, RTLIL::Wire *onei_n_i, + + RTLIL::Wire *&ppij_o, RTLIL::Wire *&nxj_o) + { + + std::string empty; + // nxj_in = xnor(xj,negi) + // nxj_o = xnj_in, + // ppij = ~( (nxj_m1_i | twoi_n_i) & (nxj_int | onei_n_i)); + nxj_o = mk_ugate2(ID($xnor), name, xj_i, negi_i, empty); + RTLIL::Wire *or1 = mk_ugate2(ID($or), name, nxj_m1_i, twoi_n_i, empty); + RTLIL::Wire *or2 = mk_ugate2(ID($or), name, nxj_o, onei_n_i, empty); + ppij_o = mk_ugate1(ID($not), name, mk_ugate2(ID($and), name, or1, or2, empty), empty); + } + + /* + In signed case 1st two bits best realised + using non-booth encoded logic. We can save a booth + encoder for the first couple of bits. + */ + void BuildBoothQ1(std::string &name, RTLIL::Wire *negi_i, RTLIL::Wire *cori_i, RTLIL::Wire *x0_i, RTLIL::Wire *x1_i, RTLIL::Wire *y0_i, + RTLIL::Wire *y1_i, + + RTLIL::Wire *&nxj_o, RTLIL::Wire *&cor_o, RTLIL::Wire *&pp0_o, RTLIL::Wire *&pp1_o + + ) + { + /* + assign NXJO = ~(X1 ^ NEGI); + assign PP0 = (X0 & Y0); + //and terms for multiply + wire pp1_1_int = X1 & Y0; + wire pp1_2_int = X0 & Y1; + //sum generation for pp[1] + assign PP1 = pp1_1_int ^ pp1_2_int; + //correction propagation + assign CORO = (~PP1 & ~PP0)? CORI : 1'b0; + */ + std::string empty; + nxj_o = mk_ugate2(ID($xnor), name, x1_i, negi_i, empty); + pp0_o = mk_ugate2(ID($and), name, x0_i, y0_i, empty); + RTLIL::Wire *pp1_1_int = mk_ugate2(ID($and), name, x1_i, y0_i, empty); + RTLIL::Wire *pp1_2_int = mk_ugate2(ID($and), name, x0_i, y1_i, empty); + pp1_o = mk_ugate2(ID($xor), name, pp1_1_int, pp1_2_int, empty); + + RTLIL::Wire *pp1_nor_pp0 = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, pp1_o, pp0_o, empty), empty); + cor_o = mk_ugate2(ID($and), name, pp1_nor_pp0, cori_i, empty); + } + + void run() + { + log("Extracting $mul cells in module %s and generating Booth Realization:\n", log_id(module)); + for (auto cell : module->selected_cells()) { + if (cell->type.in(ID($mul))) { + RTLIL::SigSpec A = sigmap(cell->getPort(ID::A)); + RTLIL::SigSpec B = sigmap(cell->getPort(ID::B)); + RTLIL::SigSpec Y = sigmap(cell->getPort(ID::Y)); + if (GetSize(A) >= 4 && GetSize(B) >= 4 && GetSize(Y) >= 8 && + ((cell->getParam(ID::A_SIGNED).as_bool() && cell->getParam(ID::B_SIGNED).as_bool()) || + (!cell->getParam(ID::A_SIGNED).as_bool() && !cell->getParam(ID::B_SIGNED).as_bool()))) { + bool is_signed = false; + if (cell->getParam(ID::A_SIGNED).as_bool()) { + log(" By passing macc inferencing for signed multiplier -- generating booth\n"); + is_signed = true; + } else + log(" By passing macc inferencing for unsigned multiplier -- generating booth\n"); + + if (is_signed == false) /* unsigned multiplier */ { + int x_sz = GetSize(A); + int y_sz = GetSize(B); + int z_sz = GetSize(Y); + + // create a buffer for each ip + std::string buf_name = "u_mult_multiplicand_buf_"; + auto A_Buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + A_Buf->setParam(ID::A_WIDTH, x_sz); + A_Buf->setParam(ID::Y_WIDTH, x_sz); + A_Buf->setPort(ID::A, SigSpec(A)); + A_Buf->setParam(ID::A_SIGNED, false); + + std::string wire_name = "u_mult_A"; + auto A_Wire = module->addWire(new_id(wire_name, __LINE__, ""), x_sz); + + A_Buf->setPort(ID::Y, A_Wire); + + buf_name = "u_mult_multiplier_buf_"; + auto B_Buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + B_Buf->setParam(ID::A_WIDTH, y_sz); + B_Buf->setParam(ID::Y_WIDTH, y_sz); + B_Buf->setPort(ID::A, SigSpec(B)); + B_Buf->setParam(ID::A_SIGNED, false); + + wire_name = "u_mult_B"; + auto B_Wire = module->addWire(new_id(wire_name, __LINE__, ""), y_sz); + B_Buf->setPort(ID::Y, B_Wire); + + buf_name = "u_mult_result_buf_"; + auto Z_Buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + Z_Buf->setParam(ID::A_WIDTH, z_sz); + Z_Buf->setParam(ID::Y_WIDTH, z_sz); + Z_Buf->setPort(ID::Y, SigSpec(Y)); + Z_Buf->setParam(ID::A_SIGNED, false); + wire_name = "u_mult_Z"; + auto Z_Wire = module->addWire(new_id(wire_name, __LINE__, ""), z_sz); + Z_Buf->setPort(ID::A, Z_Wire); + + CreateBoothUMult(module, x_sz, y_sz, z_sz, + A_Wire, // multiplicand + B_Wire, // multiplier(scanned) + Z_Wire // result + ); + module->remove(cell); + booth_counter++; + continue; + } + + else /*signed multiplier */ { + int x_sz = GetSize(A); + int y_sz = GetSize(B); + int z_sz = GetSize(Y); + + // make wire of correct size to feed multiplier + Wire *expanded_A = module->addWire(NEW_ID, x_sz); + + Wire *expanded_B = module->addWire(NEW_ID, y_sz); + + std::string buf_name = "expand_a_buf_"; + auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setParam(ID::A_WIDTH, x_sz); + buf->setParam(ID::Y_WIDTH, x_sz); + buf->setPort(ID::A, SigSpec(A)); + buf->setParam(ID::A_SIGNED, is_signed ? true : false); + buf->setPort(ID::Y, SigSpec(expanded_A)); + + buf_name = "expand_b_buf_"; + buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setPort(ID::A, SigSpec(B)); + buf->setParam(ID::A_WIDTH, y_sz); + buf->setParam(ID::Y_WIDTH, y_sz); + + buf->setParam(ID::A_SIGNED, is_signed ? true : false); + buf->setPort(ID::Y, SigSpec(expanded_B)); + + // + // Make a wire to take the expanded output + // wires + // + + Wire *expanded_Y = module->addWire(NEW_ID, (is_signed == false ? z_sz + 2 : z_sz)); + CreateBoothSMult(module, x_sz, y_sz, (is_signed == false ? z_sz + 2 : z_sz), + expanded_A, // multiplicand + expanded_B, // multiplier(scanned) + expanded_Y // result + ); + // now connect the expanded_Y with a tap to fill out sig Spec Y + + buf_name = "reducer_buf_"; + buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setPort(ID::A, expanded_Y); + buf->setParam(ID::A_WIDTH, is_signed == false ? z_sz + 2 : z_sz); + buf->setParam(ID::Y_WIDTH, z_sz); + buf->setParam(ID::A_SIGNED, is_signed ? true : false); + // wire in output Y + buf->setPort(ID::Y, SigSpec(Y)); + + // kill original multiplier + module->remove(cell); + booth_counter++; + continue; + } + } + } + } + } + + /* + Build Unsigned Multiplier. + ------------------------- + Create a booth unsigned multiplier. + Uses a generic booth multiplier with + extra row of decoders and extended multiplier + */ + + void CreateBoothUMult(RTLIL::Module *module, int x_sz, int y_sz, int z_sz, + RTLIL::Wire *X, // multiplicand + RTLIL::Wire *Y, // multiplier + RTLIL::Wire *Z) + { // result + + std::vector one_int; + std::vector two_int; + std::vector s_int; + std::vector sb_int; + int encoder_count = 0; + + BuildBoothUMultEncoders(Y, y_sz, one_int, two_int, s_int, sb_int, module, encoder_count); + + // Build the decoder rows + // format of each Partial product to be passed to CSA + // tree builder: + // + // Bits to be added + // Shift + // Sign bit to be added + // + std::vector, int, RTLIL::Wire *>> ppij_int; + + static int constant_ix; + constant_ix++; + std::string buf_name = "constant_buf_" + std::to_string(constant_ix); + auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + RTLIL::Wire *constant_one = module->addWire(new_id(buf_name, __LINE__, ""), 1); + buf->setPort(ID::A, State::S1); + buf->setParam(ID::A_WIDTH, 1); + buf->setParam(ID::Y_WIDTH, 1); + buf->setParam(ID::A_SIGNED, true); + buf->setPort(ID::Y, constant_one); + + constant_ix++; + buf_name = "constant_buf_" + std::to_string(constant_ix); + buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + RTLIL::Wire *constant_zero = module->addWire(new_id(buf_name, __LINE__, ""), 1); + buf->setPort(ID::A, State::S0); + buf->setParam(ID::A_WIDTH, 1); + buf->setParam(ID::Y_WIDTH, 1); + buf->setParam(ID::A_SIGNED, true); + buf->setPort(ID::Y, constant_zero); + + // Row 0: special case 1. Format S/.S.S.C.Data + std::vector ppij_row_0; + BuildBoothUMultDecoderRow0(module, X, s_int, sb_int, one_int, two_int, ppij_row_0); + + // data, shift, sign + ppij_int.push_back(std::make_tuple(ppij_row_0, 0, s_int[0])); + + for (int i = 1; i < encoder_count - 2; i++) { + // format 1,S.Data.shift = encoder_ix*2,sign = sb_int[i] + std::vector ppij_row_n; + + BuildBoothUMultDecoderRowN(module, + X, // multiplicand + one_int[i], two_int[i], s_int[i], sb_int[i], ppij_row_n, constant_one, i, + false, // include sign + false // include constant + ); + // data, shift, sign + ppij_int.push_back(std::make_tuple(ppij_row_n, i * 2, s_int[i])); + } + + // Build second to last row + // format S/,Data + sign bit + std::vector ppij_row_em1; + BuildBoothUMultDecoderRowN(module, X, one_int[encoder_count - 2], two_int[encoder_count - 2], s_int[encoder_count - 2], + sb_int[encoder_count - 2], ppij_row_em1, constant_one, encoder_count - 2, + false, // include sign + true // no constant + ); + ppij_int.push_back(std::make_tuple(ppij_row_em1, (encoder_count - 2) * 2, s_int[encoder_count - 2])); + // Build last row + // format Data + sign bit + std::vector ppij_row_e; + BuildBoothUMultDecoderRowN(module, X, one_int[encoder_count - 1], two_int[encoder_count - 1], s_int[encoder_count - 1], + sb_int[encoder_count - 1], ppij_row_e, constant_one, encoder_count - 1, + true, // no sign + true // no constant + ); + ppij_int.push_back(std::make_tuple(ppij_row_e, (encoder_count - 1) * 2, s_int[encoder_count - 1])); + + // Debug dump out partial products + // DebugDumpPP(ppij_int); + + // Summation of Partial Products (Wallace Tree) + std::vector> aligned_pp; + aligned_pp.resize(encoder_count + 1); // make an entirely redundant row + // just for sign bit in lsb. (We then filter this out). + + // resize all to be same size as z + for (int i = 0; i < encoder_count + 1; i++) + aligned_pp[i].resize(z_sz); + + AlignPP(x_sz, z_sz, ppij_int, aligned_pp); + + // Debug: dump out aligned partial products. + // Later on yosys will clean up unused constants + // DebugDumpAlignPP(aligned_pp); + + std::vector s_vec; + std::vector c_vec; + std::vector> debug_csa_trees; + + debug_csa_trees.resize(z_sz); + + BuildCSATree(module, aligned_pp, s_vec, c_vec, debug_csa_trees); + + // Debug code: Dump out the csa trees + // DumpCSATrees(debug_csa_trees); + // Build the CPA to do the final accumulation. + BuildCPA(module, s_vec, c_vec, Z); + } + + /* + Build Row 0 of decoders + */ + + void BuildBoothUMultDecoderRow0(RTLIL::Module *module, + RTLIL::Wire *X, // multiplicand + std::vector &s_int, std::vector &sb_int, std::vector &one_int, + std::vector &two_int, std::vector &ppij_vec) + { + (void)module; + int x_sz = GetSize(X); + + // lsb + std::string dec_name = "row0_lsb_dec"; + + RTLIL::Wire *ppij; + std::string ppij_name = "ppij_0_0"; + BuildBur4d_lsb(dec_name, mk_wireFromSigSpec(SigSpec(X, 0, 1)), one_int[0], s_int[0], ppij, ppij_name); + ppij_vec.push_back(ppij); + + // 1..xsize -1 + for (int i = 1; i < x_sz; i++) { + dec_name = "row0_dec_" + std::to_string(i); + RTLIL::Wire *ppij; + BuildBur4d_n(dec_name, mk_wireFromSigSpec(SigSpec(X, i, 1)), mk_wireFromSigSpec(SigSpec(X, i - 1, 1)), one_int[0], two_int[0], + s_int[0], ppij); + ppij_vec.push_back(ppij); + } + + // The redundant bit. Duplicate decoding of last bit. + dec_name = "row0_dec_msb"; + BuildBur4d_msb(dec_name, mk_wireFromSigSpec(SigSpec(X, x_sz - 1, 1)), two_int[0], s_int[0], ppij); + ppij_vec.push_back(ppij); + + // append the sign bits + ppij_vec.push_back(s_int[0]); + ppij_vec.push_back(s_int[0]); + ppij_vec.push_back(sb_int[0]); + } + + // Build a generic row of decoders. + + void BuildBoothUMultDecoderRowN(RTLIL::Module *module, + RTLIL::Wire *X, // multiplicand + RTLIL::Wire *one_int, RTLIL::Wire *two_int, RTLIL::Wire *s_int, RTLIL::Wire *sb_int, + std::vector &ppij_vec, RTLIL::Wire *constant_one, int row_ix, bool no_sign, bool no_constant) + { + (void)module; + int x_sz = GetSize(X); + + // lsb + std::string ppij_name = "ppij_" + std::to_string(row_ix) + "_0"; + RTLIL::Wire *ppij = nullptr; + std::string empty; + std::string dec_name = "row" + std::to_string(row_ix) + "_lsb_dec"; + BuildBur4d_lsb(dec_name, mk_wireFromSigSpec(SigSpec(X, 0, 1)), one_int, s_int, ppij, empty); + + ppij_vec.push_back(ppij); + + // core bits + for (int i = 1; i < x_sz; i++) { + + dec_name = "row_" + std::to_string(row_ix) + "_dec_" + std::to_string(i); + RTLIL::Wire *ppij = nullptr; + BuildBur4d_n(dec_name, mk_wireFromSigSpec(SigSpec(X, i, 1)), mk_wireFromSigSpec(SigSpec(X, i - 1, 1)), one_int, two_int, + s_int, ppij); + ppij_vec.push_back(ppij); + } + + // redundant bit + + dec_name = "row_dec_red"; + BuildBur4d_msb(dec_name, mk_wireFromSigSpec(SigSpec(X, x_sz - 1, 1)), two_int, s_int, ppij); + ppij_vec.push_back(ppij); + + // sign bit + if (no_sign == false) // if no sign is false then make a sign bit + ppij_vec.push_back(sb_int); + + // constant bit + if (no_constant == false) { // if non constant is false make a constant bit + ppij_vec.push_back(constant_one); + } + } + + void DebugDumpAlignPP(std::vector> &aligned_pp) + { + printf("Aligned & Padded Partial products\n"); + int pp_ix = 0; + for (auto pp_row : aligned_pp) { + printf("PP_%d \t", pp_ix); + for (unsigned i = 0; i < pp_row.size(); i++) + printf("[%d] %s ", i, pp_row[i] == nullptr ? " 0 " : pp_row[i]->name.c_str()); + printf("\n"); + pp_ix++; + } + } + + // Debug routines to inspect intermediate results + void DebugDumpPP(std::vector, int, RTLIL::Wire *>> &ppij_int) + { + printf("Debug dump of partial products\n"); + int pp_ix = 0; + + for (auto pp : ppij_int) { + int shift = get<1>(pp); + RTLIL::Wire *sign_bit = get<2>(pp); + + printf("PP %d\n", pp_ix); + printf("\tShift %d\n", shift); + printf("\tData (0 lsb)\n\t"); + int ix = 0; + + for (auto pp_wire : get<0>(pp)) { + RTLIL::IdString wire_name = pp_wire->name; + + printf(" [%d]:%s ", ix, wire_name.c_str()); + ix++; + } + printf("\n"); + printf("\tSign bit to add in: %s\n", sign_bit->name.c_str()); + + pp_ix++; + } + } + + void DumpCSATrees(std::vector> &debug_csa_trees) + { + int i = 0; + for (auto csa_tree : debug_csa_trees) { + printf("CSA Tree column %d\n", i); + int ix = 0; + for (auto csa_elem : csa_tree) { + printf("\tCell %d %s type %s\n", ix, csa_elem->name.c_str(), csa_elem->type.c_str()); + if (csa_elem->getPort(ID::A) == State::S0) + printf("\tA set to constant 0\n"); + else if (csa_elem->getPort(ID::A) == State::S1) + printf("\tA set to constant 1\n"); + else + printf("\tA driven by %s\n", csa_elem->getPort(ID::A).as_wire()->name.c_str()); + + if (csa_elem->getPort(ID::B) == State::S0) + printf("\tB set to constant 0\n"); + else if (csa_elem->getPort(ID::B) == State::S1) + printf("\tB set to constant 1\n"); + else + printf("\tB driven by %s\n", csa_elem->getPort(ID::B).as_wire()->name.c_str()); + + if (csa_elem->getPort(ID::C) == State::S0) + printf("\tC set to constant 0\n"); + else if (csa_elem->getPort(ID::C) == State::S1) + printf("\tC set to constant 1\n"); + else + printf("\tC driven by %s\n", csa_elem->getPort(ID::C).as_wire()->name.c_str()); + + printf("Carry out: %s\n", csa_elem->getPort(ID::X).as_wire()->name.c_str()); + printf("Sum out: %s\n", csa_elem->getPort(ID::Y).as_wire()->name.c_str()); + + ix++; + } + i++; + } + } + + void BuildCSATree(RTLIL::Module *module, std::vector> &bits_to_reduce, std::vector &s_vec, + std::vector &c_vec, std::vector> &debug_csa_trees) + { + + if (!(bits_to_reduce.size() > 0)) + return; + + int column_size = bits_to_reduce[0].size(); + int row_size = bits_to_reduce.size(); + std::vector carry_bits_to_add_to_next_column; + + for (int column_ix = 0; column_ix < column_size; column_ix++) { + + // get the bits in this column. + std::vector column_bits; + for (int row_ix = 0; row_ix < row_size; row_ix++) { + if (bits_to_reduce[row_ix].at(column_ix)) + column_bits.push_back(bits_to_reduce[row_ix].at(column_ix)); + } + for (auto c : carry_bits_to_add_to_next_column) { +#ifdef DEBUG_CSA + printf("\t Propagating column bit %s to column %d from column %d\n", c->name.c_str(), column_ix, column_ix - 1); +#endif + column_bits.push_back(c); + } + + carry_bits_to_add_to_next_column.resize(0); + +#ifdef DEBUG_CSA + printf("Column %d Reducing %d bits\n", column_ix, column_bits.size()); + for (auto b : column_bits) { + printf("\t %s\n", b->name.c_str()); + } + printf("\n"); +#endif + + RTLIL::Wire *s = nullptr; + RTLIL::Wire *c = nullptr; +#ifdef DEBUG_CSA + int csa_count_before = debug_csa_trees[column_ix].size(); +#endif + + ReduceBits(module, column_ix, column_bits, s, c, carry_bits_to_add_to_next_column, debug_csa_trees); + + s_vec.push_back(s); + c_vec.push_back(c); + +#ifdef DEBUG_CSA + int csa_count_after = debug_csa_trees[column_ix].size(); + + printf("Column %d Created %d csa tree elements\n", column_ix, csa_count_after - csa_count_before); +#endif + } + } + + /* + Alignment: + --------- + + Concept traverse from last row. + Pad row by shift + Add sign bit from prior row to 2 bits right of end of data. + + Example + + SCDDDDDDD- +S + DDDDDDDD_ + + ==> + SCDDDDDDD- + DDDDDDDD_S <-- prior rows sign bit added 2 columns to right on next row. + + Pad out rows with zeros and left the opt pass clean them up. + + */ + void AlignPP(int x_sz, int z_sz, std::vector, int, RTLIL::Wire *>> &ppij_int, + std::vector> &aligned_pp) + { + unsigned aligned_pp_ix = aligned_pp.size() - 1; + + // default is zero for everything (so don't have to think to hard + // about padding). + + for (unsigned i = 0; i < aligned_pp.size(); i++) { + for (int j = 0; j < z_sz; j++) { + aligned_pp[i][j] = nullptr; + } + } + + // for very last row we just have the sign bit + // Note that the aligned_pp is one row bigger + // than the ppij_int. We put the sign bit + // in first column of the last partial product + // which is at index corresponding to size of multiplicand + { + RTLIL::Wire *prior_row_sign = nullptr; + prior_row_sign = get<2>(ppij_int[aligned_pp_ix - 1]); + if (prior_row_sign) { + log_assert(aligned_pp_ix < aligned_pp.size()); + log_assert(x_sz - 1 < (int)(aligned_pp[aligned_pp_ix].size())); + aligned_pp[aligned_pp_ix][x_sz - 1] = prior_row_sign; + } + } + + for (int row_ix = aligned_pp_ix - 1; row_ix >= 0; row_ix--) { + int shift_amount = get<1>(ppij_int[row_ix]); + RTLIL::Wire *prior_row_sign = nullptr; + + // copy in data + unsigned copy_ix = shift_amount; + for (auto w : get<0>(ppij_int[row_ix])) { + if (copy_ix < aligned_pp[row_ix].size()) { + aligned_pp[row_ix][copy_ix] = w; + } + copy_ix++; + } + + // copy in the sign bit from the prior row + if (row_ix > 0) { + // if sign bit on prior row, copy in + // the destination of the sign bit is the (row_ix -1)*2 + // eg destination for sign bit for row 0 is 0. + // eg destination for sign bit for row 1 is 1 + prior_row_sign = get<2>(ppij_int[row_ix - 1]); + copy_ix = (row_ix - 1) * 2; + aligned_pp[row_ix][copy_ix] = prior_row_sign; + } + } + } + + /* + Build a Carry Propagate Adder + ----------------------------- + First build the sum and carry vectors to be added. + Axioms: + c_vec.size() == s_vec.size() + result.size() == s_vec.size() + 2; (assume result is reserved to hold correct size) + */ + void BuildCPA(RTLIL::Module *module, std::vector &s_vec, std::vector &c_vec, RTLIL::Wire *result) + { + + static int cpa_id; + cpa_id++; + + RTLIL::Wire *carry = nullptr; + + log_assert(s_vec.size() == c_vec.size()); + + for (unsigned n = 0; n < s_vec.size(); n++) { + std::string carry_name; + + // Base Case: Bit 0 is sum 0 + if (n == 0) { + std::string buf_name = "base_buf_" + std::to_string(cpa_id) + "_" + std::to_string(n); + auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setPort(ID::A, s_vec[0]); + buf->setParam(ID::A_WIDTH, 1); + buf->setParam(ID::Y_WIDTH, 1); + buf->setParam(ID::A_SIGNED, false); + buf->setPort(ID::Y, SigSpec(result, 0, 1)); + +#ifdef DEBUG_CPA + printf("CPA bit [%d] Cell %s IP 0 %s \n", n, buf->name.c_str(), s_vec[0]->name.c_str()); +#endif + } + + // + // Base Case + // c,s = ha(s_vec[1],c_vec[0]) + // + else if (n == 1) { + std::string ha_name = "cpa_" + std::to_string(cpa_id) + "_ha_" + std::to_string(n); + RTLIL::Wire *ha_op; + BuildHa(ha_name, s_vec[n], c_vec[n - 1], ha_op, carry); + + connect_sigSpecToWire(ha_op, SigSpec(result, n, 1)); + +#ifdef DEBUG_CPA + printf("CPA bit [%d] Cell %s IPs [%s] [%s] \n", n, ha_cell->name.c_str(), s_vec[n]->name.c_str(), + c_vec[n - 1]->name.c_str()); +#endif + + } + // End Case + else if (n == (unsigned)((s_vec.size() - 1))) { + // Make the carry results.. Two extra bits after fa. + std::string fa_name = "cpa_" + std::to_string(cpa_id) + "_fa_" + std::to_string(n); + auto fa_cell = module->addCell(new_id(fa_name, __LINE__, ""), ID($fa)); + fa_cell->setParam(ID::WIDTH, 1); + carry_name = "cpa_" + std::to_string(cpa_id) + "carry_" + std::to_string(n); + fa_cell->setPort(ID::A, s_vec[n]); + fa_cell->setPort(ID::B, c_vec[n - 1]); + fa_cell->setPort(ID::C, carry); + // wire in result and carry out + fa_cell->setPort(ID::Y, SigSpec(result, n, 1)); + + // make a new carry bit for carry out... + carry = module->addWire(new_id(carry_name, __LINE__, ""), 1); + fa_cell->setPort(ID::X, carry); + +#ifdef DEBUG_CPA + printf("CPA bit [%d] Cell %s IPs [%s] [%s] [%s]\n", n, fa_cell->name.c_str(), s_vec[n]->name.c_str(), + c_vec[n - 1]->name.c_str(), carry->name.c_str()); +#endif + if (n + 1 < (unsigned)(GetSize(result))) { + // Now make a half adder: c_vec[n] = carry + std::string ha_name = "cpa_" + std::to_string(cpa_id) + "_ha_" + std::to_string(n); + RTLIL::Wire *ha_sum; + RTLIL::Wire *ha_carry; + BuildHa(ha_name, c_vec[n], carry, ha_sum, ha_carry); + + if (n + 1 < (unsigned)GetSize(result)) + connect_sigSpecToWire(ha_sum, SigSpec(result, n + 1, 1)); + if (n + 2 < (unsigned)GetSize(result)) + connect_sigSpecToWire(ha_carry, SigSpec(result, n + 2, 1)); + } + } + // Step case + else { + std::string fa_name = "cpa_" + std::to_string(cpa_id) + "_fa_" + std::to_string(n); + auto fa_cell = module->addCell(new_id(fa_name, __LINE__, ""), ID($fa)); + fa_cell->setParam(ID::WIDTH, 1); + + carry_name = "cpa_" + std::to_string(cpa_id) + "carry_" + std::to_string(n); + fa_cell->setPort(ID::A, s_vec[n]); + fa_cell->setPort(ID::B, c_vec[n - 1]); + fa_cell->setPort(ID::C, carry); + // wire in result and carry out + fa_cell->setPort(ID::Y, SigSpec(result, n, 1)); + // make a new carry bit for carry out... + carry = module->addWire(new_id(carry_name, __LINE__, ""), 1); + fa_cell->setPort(ID::X, carry); + +#ifdef DEBUG_CPA + printf("CPA bit [%d] Cell %s IPs [%s] [%s] [%s]\n", n, fa_cell->name.c_str(), s_vec[n]->name.c_str(), + c_vec[n - 1]->name.c_str(), carry->name.c_str()); +#endif + } + } + } + + // Sum the bits in the current column + // Pass the carry bits from each csa to the next + // column for summation. + + void ReduceBits(RTLIL::Module *module, int column_ix, std::vector &column_bits, RTLIL::Wire *&s_result, RTLIL::Wire *&c_result, + std::vector &carry_bits_to_sum, std::vector> &debug_csa_trees) + { + + int csa_ix = 0; + int column_size = column_bits.size(); + static int unique_id = 0; + + unique_id++; + + if (column_size > 0) { + unsigned var_ix = 0; + std::vector first_csa_ips; + // get the first 3 inputs, if possible + for (var_ix = 0; var_ix < column_bits.size() && first_csa_ips.size() != 3; var_ix++) { + if (column_bits[var_ix]) + first_csa_ips.push_back(column_bits[var_ix]); + } + + if (first_csa_ips.size() > 0) { + // build the first csa + std::string csa_name = + "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_" + std::to_string(unique_id) + "_"; + auto csa = module->addCell(NEW_ID, + // new_id(csa_name, + // __LINE__, + // ""), + ID($fa)); + csa->setParam(ID::WIDTH, 1); + debug_csa_trees[column_ix].push_back(csa); + csa_ix++; + + csa->setPort(ID::A, first_csa_ips[0]); + + if (first_csa_ips.size() > 1) + csa->setPort(ID::B, first_csa_ips[1]); + else + csa->setPort(ID::B, State::S0); + + if (first_csa_ips.size() > 2) + csa->setPort(ID::C, first_csa_ips[2]); + else + csa->setPort(ID::C, State::S0); + + std::string sum_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_s"; + auto s_wire = module->addWire(new_id(sum_wire_name, __LINE__, ""), 1); + csa->setPort(ID::Y, s_wire); + s_result = s_wire; + std::string carry_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_c"; + auto c_wire = module->addWire(new_id(carry_wire_name, __LINE__, ""), 1); + csa->setPort(ID::X, c_wire); + c_result = c_wire; + + if (var_ix <= column_bits.size() - 1) + carry_bits_to_sum.push_back(c_wire); + + // Now build the rest of the tree if we can + while (var_ix <= column_bits.size() - 1) { + std::vector csa_ips; + // get the next two variables to sum + for (; var_ix <= column_bits.size() - 1 && csa_ips.size() < 2;) { + // skip any empty bits + if (column_bits[var_ix] != nullptr) + csa_ips.push_back(column_bits[var_ix]); + var_ix++; + } + + if (csa_ips.size() > 0) { + csa_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix); + auto csa = module->addCell(new_id(csa_name, __LINE__, ""), ID($fa)); + csa->setParam(ID::WIDTH, 1); + debug_csa_trees[column_ix].push_back(csa); + + csa_ix++; + // prior level + csa->setPort(ID::A, s_wire); + csa->setPort(ID::B, csa_ips[0]); + if (csa_ips.size() > 1) + csa->setPort(ID::C, csa_ips[1]); + else + csa->setPort(ID::C, State::S0); + + carry_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_c"; + c_wire = module->addWire(new_id(carry_wire_name, __LINE__, ""), 1); + + if (var_ix <= column_bits.size() - 1) + carry_bits_to_sum.push_back(c_wire); + + sum_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_s"; + s_wire = module->addWire(new_id(sum_wire_name, __LINE__, ""), 1); + + csa->setPort(ID::X, c_wire); + csa->setPort(ID::Y, s_wire); + + s_result = s_wire; + c_result = c_wire; + } + } + } + } + } + + void BuildBoothUMultEncoders(RTLIL::Wire *Y, int y_sz, std::vector &one_int, std::vector &two_int, + std::vector &s_int, std::vector &sb_int, RTLIL::Module *module, int &encoder_ix) + { + for (int y_ix = 0; y_ix < y_sz;) { + std::string enc_name = "bur_enc_" + std::to_string(encoder_ix) + "_"; + log("Created booth encoder %s\n", enc_name.c_str()); + + std::string two_name = "two_int" + std::to_string(encoder_ix); + two_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); + + std::string one_name = "one_int" + std::to_string(encoder_ix); + one_int.push_back(module->addWire(new_id(one_name, __LINE__, ""), 1)); + + std::string s_name = "s_int" + std::to_string(encoder_ix); + s_int.push_back(module->addWire(new_id(s_name, __LINE__, ""), 1)); + + std::string sb_name = "sb_int" + std::to_string(encoder_ix); + sb_int.push_back(module->addWire(new_id(sb_name, __LINE__, ""), 1)); + + if (y_ix == 0) { + + BuildBur4e(enc_name, mk_wireFromSigSpec(State::S0), mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)), + mk_wireFromSigSpec(SigSpec(Y, y_ix + 1, 1)), one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], + sb_int[encoder_ix]); + + y_ix = y_ix + 1; + encoder_ix++; + } else { + // + // step case. If multiplier ends on a boundary + // then add an extra booth encoder bounded by + // zeroes to ensure unsigned works. + // + RTLIL::Wire *y0_wire; + RTLIL::Wire *y1_wire; + RTLIL::Wire *y2_wire; + + bool need_padded_cell = false; + + if (y_ix > y_sz - 1) { + y0_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + need_padded_cell = false; + } else { + y0_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + y_ix++; + } + + if (y_ix > y_sz - 1) { + need_padded_cell = false; + y1_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + } else { + y1_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + y_ix++; + } + + if (y_ix > y_sz - 1) { + need_padded_cell = false; + y2_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + } else { + if (y_ix == y_sz - 1) + need_padded_cell = true; + else + need_padded_cell = false; + y2_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + + BuildBur4e(enc_name, y0_wire, y1_wire, y2_wire, one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], + sb_int[encoder_ix]); + } + + encoder_ix++; + + if (need_padded_cell == true) { + + log(" Creating padded encoder for unsigned\n"); + + // make extra encoder cell + // y_ix at y0, rest 0 + + std::string enc_name = "br_enc_pad" + std::to_string(encoder_ix) + "_"; + log("Created (padded) booth encoder %s\n", enc_name.c_str()); + + std::string two_name = "two_int" + std::to_string(encoder_ix); + two_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); + + std::string one_name = "one_int" + std::to_string(encoder_ix); + one_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); + + std::string s_name = "s_int" + std::to_string(encoder_ix); + s_int.push_back(module->addWire(new_id(s_name, __LINE__, ""), 1)); + + std::string sb_name = "sb_int" + std::to_string(encoder_ix); + sb_int.push_back(module->addWire(new_id(sb_name, __LINE__, ""), 1)); + + RTLIL::Wire *one_o_int, *two_o_int, *s_o_int, *sb_o_int; + BuildBur4e(enc_name, mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)), mk_wireFromSigSpec(State::S0), + mk_wireFromSigSpec(State::S0), one_o_int, two_o_int, s_o_int, sb_o_int); + + join_wires_with_buffer(one_o_int, one_int[encoder_ix]); + join_wires_with_buffer(two_o_int, two_int[encoder_ix]); + join_wires_with_buffer(s_o_int, s_int[encoder_ix]); + join_wires_with_buffer(sb_o_int, sb_int[encoder_ix]); + y_ix++; + encoder_ix++; + } + } + } + } + + /* + Signed Multiplier + */ + + void CreateBoothSMult(RTLIL::Module *module, int x_sz, int y_sz, int z_sz, RTLIL::Wire *X, RTLIL::Wire *Y, RTLIL::Wire *Z) + { // product + unsigned enc_count = (y_sz / 2) + (((y_sz % 2) != 0) ? 1 : 0); + int dec_count = x_sz + 1; + + int fa_count = x_sz + 4; + int fa_row_count = enc_count - 1; + + log("Signed multiplier generator using low Power Negative First Booth Algorithm. Multiplicand of size %d Multiplier of size %d. " + "Result of size %d. %d encoders %d decoders\n", + x_sz, y_sz, z_sz, enc_count, dec_count); + + RTLIL::Wire *negi_n_int[enc_count]; + RTLIL::Wire *twoi_n_int[enc_count]; + RTLIL::Wire *onei_n_int[enc_count]; + RTLIL::Wire *cori_n_int[enc_count]; + + for (unsigned encoder_ix = 1; encoder_ix <= enc_count; encoder_ix++) { + std::string enc_name = "enc_" + std::to_string(encoder_ix) + "_"; + std::string negi_name = "negi_n_int" + std::to_string(encoder_ix) + "_"; + negi_n_int[encoder_ix - 1] = module->addWire(new_id(negi_name, __LINE__, ""), 1); + std::string twoi_name = "twoi_n_int_" + std::to_string(encoder_ix) + "_"; + twoi_n_int[encoder_ix - 1] = module->addWire(new_id(twoi_name, __LINE__, ""), 1); + std::string onei_name = "onei_n_int_" + std::to_string(encoder_ix) + "_"; + onei_n_int[encoder_ix - 1] = module->addWire(new_id(onei_name, __LINE__, ""), 1); + std::string cori_name = "cori_n_int_" + std::to_string(encoder_ix) + "_"; + cori_n_int[encoder_ix - 1] = module->addWire(new_id(cori_name, __LINE__, ""), 1); + + if (encoder_ix == 1) { + + BuildBr4e(enc_name, mk_wireFromSigSpec(SigSpec(State::S0)), mk_wireFromSigSpec(SigSpec(Y, 0, 1)), + mk_wireFromSigSpec(SigSpec(Y, 1, 1)), + + negi_n_int[encoder_ix - 1], twoi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], + cori_n_int[encoder_ix - 1]); + + } else { + RTLIL::Wire *y1_wire; + RTLIL::Wire *y2_wire; + RTLIL::Wire *y3_wire; + + y1_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2 - 1), 1)); //-1 + if ((encoder_ix - 1) * 2 >= (unsigned)y_sz) + y2_wire = mk_wireFromSigSpec(SigSpec(State::S0)); // constant 0 + else + y2_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2), 1)); // 0 + + if (((encoder_ix - 1) * 2 + 1) >= (unsigned)y_sz) + y3_wire = mk_wireFromSigSpec(SigSpec(State::S0)); // constant 0 + else + y3_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2 + 1), 1)); //+1 + + BuildBr4e(enc_name, y1_wire, y2_wire, y3_wire, + + negi_n_int[encoder_ix - 1], twoi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], + cori_n_int[encoder_ix - 1]); + } + } + // Decoders and PP generation + RTLIL::Wire *PPij[enc_count][dec_count]; + RTLIL::Wire *nxj[enc_count][dec_count]; + for (int encoder_ix = 1; encoder_ix <= (int)enc_count; encoder_ix++) { + for (int decoder_ix = 1; decoder_ix <= dec_count; decoder_ix++) { + std::string ppij_name = "ppij_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; + PPij[encoder_ix - 1][decoder_ix - 1] = module->addWire(new_id(ppij_name, __LINE__, ""), 1); + std::string nxj_name; + if (decoder_ix == 1) + nxj_name = "nxj_pre_dec" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; + else + nxj_name = "nxj_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; + + nxj[encoder_ix - 1][decoder_ix - 1] = module->addWire(new_id(nxj_name, __LINE__, ""), 1); + } + } + + // + // build decoder array + // + + for (int encoder_ix = 1; encoder_ix <= (int)enc_count; encoder_ix++) { + // pre-decoder + std::string pre_dec_name = "pre_dec_" + std::to_string(encoder_ix) + "_"; + + if (encoder_ix == 1) { + // quadrant 1 optimization + } else { + auto cell = module->addCell(new_id(pre_dec_name, __LINE__, ""), ID($_NOT_)); + cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + cell->setPort(ID::A, negi_n_int[encoder_ix - 1]); + cell->setPort(ID::Y, nxj[encoder_ix - 1][0]); + } + + for (int decoder_ix = 1; decoder_ix < dec_count; decoder_ix++) { + // range 1..8 + + // quadrant 1 optimization. + if ((decoder_ix == 1 || decoder_ix == 2) && encoder_ix == 1) + continue; + + std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; + + BuildBr4d(dec_name, nxj[encoder_ix - 1][decoder_ix - 1], twoi_n_int[encoder_ix - 1], + mk_wireFromSigSpec(SigSpec(X, decoder_ix - 1, 1)), negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], + PPij[encoder_ix - 1][decoder_ix - 1], nxj[encoder_ix - 1][decoder_ix]); + } + + // duplicate end for sign fix + // applies to 9th decoder (xsz+1 decoder). + std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(x_sz + 1) + "_"; + RTLIL::Wire *unused_op = nullptr; + BuildBr4d(dec_name, nxj[encoder_ix - 1][dec_count - 1], twoi_n_int[encoder_ix - 1], + mk_wireFromSigSpec(SigSpec(X, dec_count - 2, 1)), negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], + PPij[encoder_ix - 1][dec_count - 1], unused_op); + } + + // + // sum up the partial products + // + int fa_el_ix = 0; + int fa_row_ix = 0; + RTLIL::Wire *fa_sum_n[fa_row_count][fa_count]; + RTLIL::Wire *fa_carry_n[fa_row_count][fa_count]; + + for (fa_row_ix = 0; fa_row_ix < fa_row_count; fa_row_ix++) { + for (fa_el_ix = 0; fa_el_ix < fa_count; fa_el_ix++) { + + std::string fa_sum_name = "fa_sum_n_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_"; + fa_sum_n[fa_row_ix][fa_el_ix] = module->addWire(new_id(fa_sum_name, __LINE__, ""), 1); + std::string fa_carry_name = "fa_carry_n" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_"; + fa_carry_n[fa_row_ix][fa_el_ix] = module->addWire(new_id(fa_carry_name, __LINE__, ""), 1); + } + } + + // full adder creation + std::string bfa_name; + std::string exc_inv_name; + for (fa_row_ix = 0; fa_row_ix < fa_row_count; fa_row_ix++) { + for (fa_el_ix = 0; fa_el_ix < fa_count; fa_el_ix++) { + // base case: 1st row. Inputs from decoders + // Note in rest of tree inputs from prior addition and a decoder + if (fa_row_ix == 0) { + // beginning + // base case: + // first two cells: have B input hooked to 0. + if (fa_el_ix == 0) { + // quadrant 1: we hard code these using non-booth + fa_el_ix++; + + } + // step case + else if (fa_el_ix >= 2 && fa_el_ix <= x_sz) { + // middle (2...x_sz cells) + bfa_name = "bfa_0_step_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; + auto cell = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell->setParam(ID::WIDTH, 1); + cell->setPort(ID::A, PPij[0][fa_el_ix]); + cell->setPort(ID::B, PPij[1][fa_el_ix - 2]); + cell->setPort(ID::C, fa_carry_n[fa_row_ix][fa_el_ix - 1]); + cell->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); + cell->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + } + // end 3 cells: x_sz+1.2.3 + // + else { + // fa_el_ix = x_sz+1 + bfa_name = "bfa_0_se_0" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; + auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell1->setParam(ID::WIDTH, 1); + cell1->setPort(ID::A, PPij[0][x_sz]); + cell1->setPort(ID::B, PPij[1][fa_el_ix - 2]); + cell1->setPort(ID::C, fa_carry_n[fa_row_ix][fa_el_ix - 1]); + cell1->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); + cell1->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + + // exception:invert ppi + fa_el_ix++; + exc_inv_name = "bfa_0_exc_inv1_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; + auto cellinv1 = module->addCell(new_id(exc_inv_name, __LINE__, ""), ID($_NOT_)); + cellinv1->add_strpool_attribute(ID::src, cellinv1->get_strpool_attribute(ID::src)); + + RTLIL::Wire *d08_inv = module->addWire(NEW_ID, 1); + + cellinv1->setPort(ID::A, PPij[0][dec_count - 1]); + cellinv1->setPort(ID::Y, d08_inv); + + exc_inv_name = "bfa_0_exc_inv2_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; + + auto cellinv2 = module->addCell(new_id(exc_inv_name, __LINE__, ""), ID($_NOT_)); + cellinv2->add_strpool_attribute(ID::src, cellinv2->get_strpool_attribute(ID::src)); + RTLIL::Wire *d18_inv = module->addWire(NEW_ID, 1); + cellinv2->setPort(ID::A, PPij[1][dec_count - 1]); + cellinv2->setPort(ID::Y, d18_inv); + + bfa_name = "bfa_0_se_1_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; + + auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell2->setParam(ID::WIDTH, 1); + cell2->setPort(ID::A, d08_inv); + cell2->setPort(ID::B, d18_inv); + cell2->setPort(ID::C, fa_carry_n[fa_row_ix][fa_el_ix - 1]); + cell2->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); + cell2->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + + // sign extension + fa_el_ix++; + bfa_name = "bfa_0_se_2_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; + auto cell3 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell3->setParam(ID::WIDTH, 1); + cell3->setPort(ID::A, State::S0); + cell3->setPort(ID::B, State::S1); + cell3->setPort(ID::C, fa_carry_n[fa_row_ix][fa_el_ix - 1]); + cell3->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); + cell3->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + } + } + + // step case: 2nd and rest of rows. (fa_row_ix == 1...n) + // special because these are driven by a decoder and prior fa. + else { + // beginning + if (fa_el_ix == 0) { + // first two cells: have B input hooked to 0. + // column is offset by row_ix*2 + bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_base_" + std::to_string(fa_row_ix) + "_" + + std::to_string(fa_el_ix) + "_L"; + auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell1->setParam(ID::WIDTH, 1); + cell1->setPort(ID::A, fa_sum_n[fa_row_ix - 1][2]); // from prior full adder row + cell1->setPort(ID::B, State::S0); + cell1->setPort(ID::C, cori_n_int[fa_row_ix]); + cell1->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); + cell1->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + fa_el_ix++; + + bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_base_" + std::to_string(fa_row_ix) + "_" + + std::to_string(fa_el_ix) + "_L"; + auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell2->setParam(ID::WIDTH, 1); + cell2->setPort(ID::A, fa_sum_n[fa_row_ix - 1][3]); // from prior full adder row + cell2->setPort(ID::B, State::S0); + cell2->setPort(ID::C, fa_carry_n[fa_row_ix][fa_el_ix - 1]); + cell2->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); + cell2->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + } + + else if (fa_el_ix >= 2 && fa_el_ix <= x_sz + 1) { + // middle (2...x_sz+1 cells) + bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_step_" + std::to_string(fa_row_ix) + "_" + + std::to_string(fa_el_ix) + "_L"; + auto cell = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell->setParam(ID::WIDTH, 1); + cell->setPort(ID::A, fa_sum_n[fa_row_ix - 1][fa_el_ix + 2]); + cell->setPort(ID::B, PPij[fa_row_ix + 1][fa_el_ix - 2]); + cell->setPort(ID::C, fa_carry_n[fa_row_ix][fa_el_ix - 1]); + cell->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); + cell->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + } + + else if (fa_el_ix > x_sz + 1) { + // end two bits: sign extension + std::string se_inv_name; + se_inv_name = "bfa_" + std::to_string(fa_row_ix) + "_se_inv_" + std::to_string(fa_row_ix) + "_" + + std::to_string(fa_el_ix) + "_L"; + auto cellinv = module->addCell(new_id(se_inv_name, __LINE__, ""), ID($_NOT_)); + cellinv->add_strpool_attribute(ID::src, cellinv->get_strpool_attribute(ID::src)); + RTLIL::Wire *d_inv = module->addWire(NEW_ID, 1); + cellinv->setPort(ID::A, PPij[fa_row_ix + 1][dec_count - 1]); + cellinv->setPort(ID::Y, d_inv); + + bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_se_" + std::to_string(fa_row_ix) + "_" + + std::to_string(fa_el_ix) + "_L"; + auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell1->setParam(ID::WIDTH, 1); + cell1->setPort(ID::A, fa_carry_n[fa_row_ix - 1][fa_count - 1]); + cell1->setPort(ID::B, d_inv); + cell1->setPort(ID::C, fa_carry_n[fa_row_ix][fa_el_ix - 1]); + cell1->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); + cell1->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + fa_el_ix++; + + // sign extension + bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_se_" + std::to_string(fa_row_ix) + "_" + + std::to_string(fa_el_ix) + "_L"; + auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell2->setParam(ID::WIDTH, 1); + cell2->setPort(ID::A, State::S0); + cell2->setPort(ID::B, State::S1); + cell2->setPort(ID::C, fa_carry_n[fa_row_ix][fa_el_ix - 1]); + cell2->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); + cell2->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + } + } + } + } + + // instantiate the cpa + RTLIL::Wire *cpa_carry[z_sz]; + + if (x_sz + y_sz != z_sz) + log("Result of multiplier is incomplete with respect to domain of inputs\n"); + + for (int cix = 0; cix < z_sz; cix++) { + std::string cpa_cix_name = "cpa_carry_" + std::to_string(cix) + "_"; + cpa_carry[cix] = module->addWire(new_id(cpa_cix_name, __LINE__, ""), 1); + } + log(" Building cpa array for booth\n"); + for (int cpa_ix = 0; cpa_ix < z_sz; cpa_ix++) { + + // The end case where we pass the last two summands + // from prior row directly to product output + // without using a cpa cell. This is always + // 0,1 index of prior fa row + if (cpa_ix <= fa_row_count * 2 - 1) { + int fa_row_ix = cpa_ix / 2; + + std::string buf_name = + "pp_buf_" + std::to_string(cpa_ix) + "_" + "driven_by_fa_row_" + std::to_string(fa_row_ix) + "_"; + auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setPort(ID::A, fa_sum_n[fa_row_ix][0]); + buf->setParam(ID::A_WIDTH, 1); + buf->setParam(ID::Y_WIDTH, 1); + buf->setParam(ID::A_SIGNED, true); + buf->setPort(ID::Y, SigSpec(Z, cpa_ix, 1)); + + cpa_ix++; + buf_name = "pp_buf_" + std::to_string(cpa_ix) + "_" + "driven_by_fa_row_" + std::to_string(fa_row_ix) + "_"; + buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setPort(ID::A, fa_sum_n[fa_row_ix][1]); + buf->setParam(ID::A_WIDTH, 1); + buf->setParam(ID::Y_WIDTH, 1); + buf->setParam(ID::A_SIGNED, true); + buf->setPort(ID::Y, SigSpec(Z, cpa_ix, 1)); + } else { + int offset = fa_row_count * 2; + bool base_case = cpa_ix - offset == 0 ? true : false; + std::string cpa_name = "cpa_" + std::to_string(cpa_ix - offset) + "_"; + + RTLIL::Wire *ci_wire; + if (base_case) + ci_wire = cori_n_int[enc_count - 1]; + else + ci_wire = cpa_carry[cpa_ix - offset - 1]; + + RTLIL::Wire *op_wire = module->addWire(NEW_ID, 1); + BuildHa(cpa_name, fa_sum_n[fa_row_count - 1][cpa_ix - offset + 2], ci_wire, op_wire, cpa_carry[cpa_ix - offset]); + connect_sigSpecToWire(op_wire, SigSpec(Z, cpa_ix, 1)); + } + } + + // + // instantiate the quadrant 1 cell. This is the upper right + // quadrant which can be realized using non-booth encoded logic. + // + std::string q1_name = "icb_booth_q1_"; + + RTLIL::Wire *pp0_o_int; + RTLIL::Wire *pp1_o_int; + RTLIL::Wire *nxj_o_int; + RTLIL::Wire *cor_o_int; + + BuildBoothQ1(q1_name, + negi_n_int[0], // negi + cori_n_int[0], // cori + + mk_wireFromSigSpec(SigSpec(X, 0, 1)), // x0 + mk_wireFromSigSpec(SigSpec(X, 1, 1)), // x1 + mk_wireFromSigSpec(SigSpec(Y, 0, 1)), // y0 + mk_wireFromSigSpec(SigSpec(Y, 1, 1)), // y1 + + nxj_o_int, cor_o_int, pp0_o_int, pp1_o_int); + + join_wires_with_buffer(pp0_o_int, fa_sum_n[0][0]); + join_wires_with_buffer(pp1_o_int, fa_sum_n[0][1]); + join_wires_with_buffer(cor_o_int, fa_carry_n[0][1]); + join_wires_with_buffer(nxj_o_int, nxj[0][2]); + } +}; + +struct MultPass : public Pass { + MultPass() : Pass("multpass") {} + void execute(vector args, RTLIL::Design *design) override + { + (void)args; + log("Multiplier Pass. Generating Booth Multiplier structures for signed/unsigned multipliers of 4 bits or more\n"); + for (auto mod : design->selected_modules()) + if (!mod->has_processes_warn()) { + MultPassWorker worker(mod); + worker.run(); + } + } +} MultPass; + +PRIVATE_NAMESPACE_END From 41b34a19353dbbe00aa08f3561e25e0bfa4c84d2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 7 Sep 2023 00:14:30 +0000 Subject: [PATCH 017/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 907891db33f..9474d37a19d 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+3 +YOSYS_VER := 0.33+6 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 0c2a99ca475dfc912ccc211afb1264a7e8fb8247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 7 Sep 2023 14:46:59 +0200 Subject: [PATCH 018/173] techmap: Test the Booth multiplier --- tests/techmap/booth.ys | 1 + tests/techmap/booth_map_script.ys_ | 1 + 2 files changed, 2 insertions(+) create mode 100644 tests/techmap/booth.ys create mode 100644 tests/techmap/booth_map_script.ys_ diff --git a/tests/techmap/booth.ys b/tests/techmap/booth.ys new file mode 100644 index 00000000000..17e20245693 --- /dev/null +++ b/tests/techmap/booth.ys @@ -0,0 +1 @@ +test_cell -script booth_map_script.ys_ $mul diff --git a/tests/techmap/booth_map_script.ys_ b/tests/techmap/booth_map_script.ys_ new file mode 100644 index 00000000000..0f323bdd863 --- /dev/null +++ b/tests/techmap/booth_map_script.ys_ @@ -0,0 +1 @@ +multpass From 25a33d408280ba496366ef282506521a4caef305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 7 Sep 2023 14:56:56 +0200 Subject: [PATCH 019/173] techmap: Make the Booth test deterministic --- tests/techmap/booth.ys | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/techmap/booth.ys b/tests/techmap/booth.ys index 17e20245693..f1dce1f3b27 100644 --- a/tests/techmap/booth.ys +++ b/tests/techmap/booth.ys @@ -1 +1 @@ -test_cell -script booth_map_script.ys_ $mul +test_cell -s 1694091355 -n 1000 -script booth_map_script.ys_ $mul From 411acc4a0a27a6b3cb198faa63f6e501a1b8df19 Mon Sep 17 00:00:00 2001 From: andyfox-rushc Date: Fri, 8 Sep 2023 13:41:31 -0700 Subject: [PATCH 020/173] Fixed edge size cases for signed/unsigned booth generator --- passes/techmap/multpass.cc | 195 +++++++++++++++++++++++++------------ 1 file changed, 135 insertions(+), 60 deletions(-) diff --git a/passes/techmap/multpass.cc b/passes/techmap/multpass.cc index e55a0441448..9981250ae08 100644 --- a/passes/techmap/multpass.cc +++ b/passes/techmap/multpass.cc @@ -295,45 +295,85 @@ struct MultPassWorker { int y_sz = GetSize(B); int z_sz = GetSize(Y); - // create a buffer for each ip - std::string buf_name = "u_mult_multiplicand_buf_"; - auto A_Buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - A_Buf->setParam(ID::A_WIDTH, x_sz); - A_Buf->setParam(ID::Y_WIDTH, x_sz); - A_Buf->setPort(ID::A, SigSpec(A)); - A_Buf->setParam(ID::A_SIGNED, false); - - std::string wire_name = "u_mult_A"; - auto A_Wire = module->addWire(new_id(wire_name, __LINE__, ""), x_sz); - - A_Buf->setPort(ID::Y, A_Wire); - - buf_name = "u_mult_multiplier_buf_"; - auto B_Buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - B_Buf->setParam(ID::A_WIDTH, y_sz); - B_Buf->setParam(ID::Y_WIDTH, y_sz); - B_Buf->setPort(ID::A, SigSpec(B)); - B_Buf->setParam(ID::A_SIGNED, false); - - wire_name = "u_mult_B"; - auto B_Wire = module->addWire(new_id(wire_name, __LINE__, ""), y_sz); - B_Buf->setPort(ID::Y, B_Wire); - - buf_name = "u_mult_result_buf_"; - auto Z_Buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - Z_Buf->setParam(ID::A_WIDTH, z_sz); - Z_Buf->setParam(ID::Y_WIDTH, z_sz); - Z_Buf->setPort(ID::Y, SigSpec(Y)); - Z_Buf->setParam(ID::A_SIGNED, false); - wire_name = "u_mult_Z"; - auto Z_Wire = module->addWire(new_id(wire_name, __LINE__, ""), z_sz); - Z_Buf->setPort(ID::A, Z_Wire); - - CreateBoothUMult(module, x_sz, y_sz, z_sz, - A_Wire, // multiplicand - B_Wire, // multiplier(scanned) - Z_Wire // result + // To simplify the generator size the arguments + // to be the same. Then allow logic synthesis to + // clean things up. Size to biggest + + int x_sz_revised = x_sz; + int y_sz_revised = y_sz; + + if (x_sz != y_sz) { + if (x_sz < y_sz) { + if (y_sz % 2 != 0) { + x_sz_revised = y_sz + 1; + y_sz_revised = y_sz + 1; + } else + x_sz_revised = y_sz; + + log("Resized x to %d ", x_sz_revised); + } else { + if (x_sz % 2 != 0) { + y_sz_revised = x_sz + 1; + x_sz_revised = x_sz + 1; + } else + y_sz_revised = x_sz; + log("Resized y to %d ", y_sz_revised); + } + } else { + if (x_sz % 2 != 0) { + y_sz_revised = y_sz + 1; + x_sz_revised = x_sz + 1; + } + } + + log_assert((x_sz_revised == y_sz_revised) && (x_sz_revised % 2 == 0) && (y_sz_revised % 2 == 0)); + + Wire *expanded_A = module->addWire(NEW_ID, x_sz_revised); + Wire *expanded_B = module->addWire(NEW_ID, y_sz_revised); + + std::string buf_name = "expand_a_buf_"; + auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setParam(ID::A_WIDTH, x_sz); + buf->setParam(ID::Y_WIDTH, x_sz_revised); + buf->setPort(ID::A, SigSpec(A)); + buf->setParam(ID::A_SIGNED, false); + buf->setPort(ID::Y, SigSpec(expanded_A)); + + buf_name = "expand_b_buf_"; + buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setPort(ID::A, SigSpec(B)); + buf->setParam(ID::A_WIDTH, y_sz); + buf->setParam(ID::Y_WIDTH, y_sz_revised); + buf->setParam(ID::A_SIGNED, false); + buf->setPort(ID::Y, SigSpec(expanded_B)); + + // Make sure output domain is big enough to take + // all combinations. + // Later logic synthesis will kill unused + // portions of the output domain. + + unsigned required_op_size = x_sz_revised + y_sz_revised; + + Wire *expanded_Y = module->addWire(NEW_ID, required_op_size); + + CreateBoothUMult(module, x_sz_revised, y_sz_revised, required_op_size, + expanded_A, // multiplicand + expanded_B, // multiplier(scanned) + expanded_Y // result ); + + // now connect the expanded_Y with a tap to fill out sig Spec Y + + log("Adding reducer on output from %u to %u ", required_op_size, z_sz); + buf_name = "reducer_buf_"; + buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setPort(ID::A, expanded_Y); + buf->setParam(ID::A_WIDTH, required_op_size); + buf->setParam(ID::Y_WIDTH, z_sz); // The real user width + buf->setParam(ID::A_SIGNED, false); + // wire in output Y + buf->setPort(ID::Y, SigSpec(Y)); + module->remove(cell); booth_counter++; continue; @@ -344,47 +384,81 @@ struct MultPassWorker { int y_sz = GetSize(B); int z_sz = GetSize(Y); - // make wire of correct size to feed multiplier - Wire *expanded_A = module->addWire(NEW_ID, x_sz); - - Wire *expanded_B = module->addWire(NEW_ID, y_sz); + // To simplify the generator size the arguments + // to be the same. Then allow logic synthesis to + // clean things up. Size to biggest + + int x_sz_revised = x_sz; + int y_sz_revised = y_sz; + + if (x_sz != y_sz) { + if (x_sz < y_sz) { + if (y_sz % 2 != 0) { + x_sz_revised = y_sz + 1; + y_sz_revised = y_sz + 1; + } else + x_sz_revised = y_sz; + + log("Resized x to %d ", x_sz_revised); + } else { + if (x_sz % 2 != 0) { + y_sz_revised = x_sz + 1; + x_sz_revised = x_sz + 1; + } else + y_sz_revised = x_sz; + log("Resized y to %d ", y_sz_revised); + } + } else { + if (x_sz % 2 != 0) { + y_sz_revised = y_sz + 1; + x_sz_revised = x_sz + 1; + } + } + + log_assert((x_sz_revised == y_sz_revised) && (x_sz_revised % 2 == 0) && (y_sz_revised % 2 == 0)); + + Wire *expanded_A = module->addWire(NEW_ID, x_sz_revised); + Wire *expanded_B = module->addWire(NEW_ID, y_sz_revised); std::string buf_name = "expand_a_buf_"; auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); buf->setParam(ID::A_WIDTH, x_sz); - buf->setParam(ID::Y_WIDTH, x_sz); + buf->setParam(ID::Y_WIDTH, x_sz_revised); buf->setPort(ID::A, SigSpec(A)); - buf->setParam(ID::A_SIGNED, is_signed ? true : false); + buf->setParam(ID::A_SIGNED, true); buf->setPort(ID::Y, SigSpec(expanded_A)); buf_name = "expand_b_buf_"; buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); buf->setPort(ID::A, SigSpec(B)); buf->setParam(ID::A_WIDTH, y_sz); - buf->setParam(ID::Y_WIDTH, y_sz); - - buf->setParam(ID::A_SIGNED, is_signed ? true : false); + buf->setParam(ID::Y_WIDTH, y_sz_revised); + buf->setParam(ID::A_SIGNED, true); buf->setPort(ID::Y, SigSpec(expanded_B)); - // - // Make a wire to take the expanded output - // wires - // + // Make sure output domain is big enough to take + // all combinations. + // Later logic synthesis will kill unused + // portions of the output domain. + + unsigned required_op_size = x_sz_revised + y_sz_revised; - Wire *expanded_Y = module->addWire(NEW_ID, (is_signed == false ? z_sz + 2 : z_sz)); - CreateBoothSMult(module, x_sz, y_sz, (is_signed == false ? z_sz + 2 : z_sz), + Wire *expanded_Y = module->addWire(NEW_ID, required_op_size); + + CreateBoothSMult(module, x_sz_revised, y_sz_revised, required_op_size, expanded_A, // multiplicand expanded_B, // multiplier(scanned) - expanded_Y // result + expanded_Y // result (sized) ); // now connect the expanded_Y with a tap to fill out sig Spec Y + log("Adding reducer on output from %u to %u ", required_op_size, z_sz); buf_name = "reducer_buf_"; buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); buf->setPort(ID::A, expanded_Y); - buf->setParam(ID::A_WIDTH, is_signed == false ? z_sz + 2 : z_sz); - buf->setParam(ID::Y_WIDTH, z_sz); - buf->setParam(ID::A_SIGNED, is_signed ? true : false); + buf->setParam(ID::A_WIDTH, required_op_size); + buf->setParam(ID::Y_WIDTH, z_sz); // The real user width + buf->setParam(ID::A_SIGNED, true); // wire in output Y buf->setPort(ID::Y, SigSpec(Y)); @@ -1451,7 +1525,7 @@ struct MultPassWorker { std::string cpa_cix_name = "cpa_carry_" + std::to_string(cix) + "_"; cpa_carry[cix] = module->addWire(new_id(cpa_cix_name, __LINE__, ""), 1); } - log(" Building cpa array for booth\n"); + log(" Building cpa array for booth for output size %u\n", z_sz); for (int cpa_ix = 0; cpa_ix < z_sz; cpa_ix++) { // The end case where we pass the last two summands @@ -1525,15 +1599,16 @@ struct MultPassWorker { }; struct MultPass : public Pass { - MultPass() : Pass("multpass") {} + MultPass() : Pass("multpass", "Map $mul to booth multipliers") {} void execute(vector args, RTLIL::Design *design) override { (void)args; - log("Multiplier Pass. Generating Booth Multiplier structures for signed/unsigned multipliers of 4 bits or more\n"); + log_header(design, "Executing multpass. Generating Booth Multiplier structures for signed/unsigned multipliers of 4 bits or more\n"); for (auto mod : design->selected_modules()) if (!mod->has_processes_warn()) { MultPassWorker worker(mod); worker.run(); + log_header(design, "Created %d booth multipliers.\n", worker.booth_counter); } } } MultPass; From 6d29dc659b19a016d33f75561c6f2dd96b42ca8f Mon Sep 17 00:00:00 2001 From: andyfox-rushc Date: Fri, 8 Sep 2023 15:34:56 -0700 Subject: [PATCH 021/173] renamed passname to booth, replaced connect_sigSpecToWire with connect, updated test script --- passes/techmap/multpass.cc | 264 +++++++++-------------------- tests/techmap/booth_map_script.ys_ | 2 +- 2 files changed, 78 insertions(+), 188 deletions(-) diff --git a/passes/techmap/multpass.cc b/passes/techmap/multpass.cc index 9981250ae08..c0e56f2ad61 100644 --- a/passes/techmap/multpass.cc +++ b/passes/techmap/multpass.cc @@ -64,16 +64,6 @@ struct MultPassWorker { // Helper routines for building architecture subcomponents - void connect_sigSpecToWire(RTLIL::Wire *ip, const SigSpec &v) - { - auto g = module->addCell(NEW_ID, ID($pos)); - g->setParam(ID::A_WIDTH, 1); - g->setParam(ID::Y_WIDTH, 1); - g->setParam(ID::A_SIGNED, false); - g->setPort(ID::A, ip); - g->setPort(ID::Y, v); - } - RTLIL::Wire *mk_wireFromSigSpec(const SigSpec &v) { @@ -274,7 +264,6 @@ struct MultPassWorker { void run() { - log("Extracting $mul cells in module %s and generating Booth Realization:\n", log_id(module)); for (auto cell : module->selected_cells()) { if (cell->type.in(ID($mul))) { RTLIL::SigSpec A = sigmap(cell->getPort(ID::A)); @@ -290,183 +279,92 @@ struct MultPassWorker { } else log(" By passing macc inferencing for unsigned multiplier -- generating booth\n"); - if (is_signed == false) /* unsigned multiplier */ { - int x_sz = GetSize(A); - int y_sz = GetSize(B); - int z_sz = GetSize(Y); - - // To simplify the generator size the arguments - // to be the same. Then allow logic synthesis to - // clean things up. Size to biggest - - int x_sz_revised = x_sz; - int y_sz_revised = y_sz; - - if (x_sz != y_sz) { - if (x_sz < y_sz) { - if (y_sz % 2 != 0) { - x_sz_revised = y_sz + 1; - y_sz_revised = y_sz + 1; - } else - x_sz_revised = y_sz; - - log("Resized x to %d ", x_sz_revised); - } else { - if (x_sz % 2 != 0) { - y_sz_revised = x_sz + 1; - x_sz_revised = x_sz + 1; - } else - y_sz_revised = x_sz; - log("Resized y to %d ", y_sz_revised); - } - } else { - if (x_sz % 2 != 0) { - y_sz_revised = y_sz + 1; - x_sz_revised = x_sz + 1; - } - } - - log_assert((x_sz_revised == y_sz_revised) && (x_sz_revised % 2 == 0) && (y_sz_revised % 2 == 0)); - - Wire *expanded_A = module->addWire(NEW_ID, x_sz_revised); - Wire *expanded_B = module->addWire(NEW_ID, y_sz_revised); + int x_sz = GetSize(A); + int y_sz = GetSize(B); + int z_sz = GetSize(Y); - std::string buf_name = "expand_a_buf_"; - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setParam(ID::A_WIDTH, x_sz); - buf->setParam(ID::Y_WIDTH, x_sz_revised); - buf->setPort(ID::A, SigSpec(A)); - buf->setParam(ID::A_SIGNED, false); - buf->setPort(ID::Y, SigSpec(expanded_A)); + // To simplify the generator size the arguments + // to be the same. Then allow logic synthesis to + // clean things up. Size to biggest - buf_name = "expand_b_buf_"; - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, SigSpec(B)); - buf->setParam(ID::A_WIDTH, y_sz); - buf->setParam(ID::Y_WIDTH, y_sz_revised); - buf->setParam(ID::A_SIGNED, false); - buf->setPort(ID::Y, SigSpec(expanded_B)); + int x_sz_revised = x_sz; + int y_sz_revised = y_sz; - // Make sure output domain is big enough to take - // all combinations. - // Later logic synthesis will kill unused - // portions of the output domain. - - unsigned required_op_size = x_sz_revised + y_sz_revised; + if (x_sz != y_sz) { + if (x_sz < y_sz) { + if (y_sz % 2 != 0) { + x_sz_revised = y_sz + 1; + y_sz_revised = y_sz + 1; + } else + x_sz_revised = y_sz; - Wire *expanded_Y = module->addWire(NEW_ID, required_op_size); + } else { + if (x_sz % 2 != 0) { + y_sz_revised = x_sz + 1; + x_sz_revised = x_sz + 1; + } else + y_sz_revised = x_sz; + } + } else { + if (x_sz % 2 != 0) { + y_sz_revised = y_sz + 1; + x_sz_revised = x_sz + 1; + } + } + log_assert((x_sz_revised == y_sz_revised) && (x_sz_revised % 2 == 0) && (y_sz_revised % 2 == 0)); + + Wire *expanded_A = module->addWire(NEW_ID, x_sz_revised); + Wire *expanded_B = module->addWire(NEW_ID, y_sz_revised); + + std::string buf_name = "expand_a_buf_"; + auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setParam(ID::A_WIDTH, x_sz); + buf->setParam(ID::Y_WIDTH, x_sz_revised); + buf->setPort(ID::A, SigSpec(A)); + buf->setParam(ID::A_SIGNED, is_signed ? true : false); + buf->setPort(ID::Y, SigSpec(expanded_A)); + + buf_name = "expand_b_buf_"; + buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setPort(ID::A, SigSpec(B)); + buf->setParam(ID::A_WIDTH, y_sz); + buf->setParam(ID::Y_WIDTH, y_sz_revised); + buf->setParam(ID::A_SIGNED, is_signed ? true : false); + buf->setPort(ID::Y, SigSpec(expanded_B)); + + // Make sure output domain is big enough to take + // all combinations. + // Later logic synthesis will kill unused + // portions of the output domain. + + unsigned required_op_size = x_sz_revised + y_sz_revised; + Wire *expanded_Y = module->addWire(NEW_ID, required_op_size); + // now connect the expanded_Y with a tap to fill out sig Spec Y + buf_name = "reducer_buf_"; + buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setPort(ID::A, expanded_Y); + buf->setParam(ID::A_WIDTH, required_op_size); + buf->setParam(ID::Y_WIDTH, z_sz); // The real user width + buf->setParam(ID::A_SIGNED, is_signed ? true : false); + // wire in output Y + buf->setPort(ID::Y, SigSpec(Y)); + + if (is_signed == false) /* unsigned multiplier */ CreateBoothUMult(module, x_sz_revised, y_sz_revised, required_op_size, expanded_A, // multiplicand expanded_B, // multiplier(scanned) expanded_Y // result ); - - // now connect the expanded_Y with a tap to fill out sig Spec Y - - log("Adding reducer on output from %u to %u ", required_op_size, z_sz); - buf_name = "reducer_buf_"; - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, expanded_Y); - buf->setParam(ID::A_WIDTH, required_op_size); - buf->setParam(ID::Y_WIDTH, z_sz); // The real user width - buf->setParam(ID::A_SIGNED, false); - // wire in output Y - buf->setPort(ID::Y, SigSpec(Y)); - - module->remove(cell); - booth_counter++; - continue; - } - - else /*signed multiplier */ { - int x_sz = GetSize(A); - int y_sz = GetSize(B); - int z_sz = GetSize(Y); - - // To simplify the generator size the arguments - // to be the same. Then allow logic synthesis to - // clean things up. Size to biggest - - int x_sz_revised = x_sz; - int y_sz_revised = y_sz; - - if (x_sz != y_sz) { - if (x_sz < y_sz) { - if (y_sz % 2 != 0) { - x_sz_revised = y_sz + 1; - y_sz_revised = y_sz + 1; - } else - x_sz_revised = y_sz; - - log("Resized x to %d ", x_sz_revised); - } else { - if (x_sz % 2 != 0) { - y_sz_revised = x_sz + 1; - x_sz_revised = x_sz + 1; - } else - y_sz_revised = x_sz; - log("Resized y to %d ", y_sz_revised); - } - } else { - if (x_sz % 2 != 0) { - y_sz_revised = y_sz + 1; - x_sz_revised = x_sz + 1; - } - } - - log_assert((x_sz_revised == y_sz_revised) && (x_sz_revised % 2 == 0) && (y_sz_revised % 2 == 0)); - - Wire *expanded_A = module->addWire(NEW_ID, x_sz_revised); - Wire *expanded_B = module->addWire(NEW_ID, y_sz_revised); - - std::string buf_name = "expand_a_buf_"; - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setParam(ID::A_WIDTH, x_sz); - buf->setParam(ID::Y_WIDTH, x_sz_revised); - buf->setPort(ID::A, SigSpec(A)); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, SigSpec(expanded_A)); - - buf_name = "expand_b_buf_"; - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, SigSpec(B)); - buf->setParam(ID::A_WIDTH, y_sz); - buf->setParam(ID::Y_WIDTH, y_sz_revised); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, SigSpec(expanded_B)); - - // Make sure output domain is big enough to take - // all combinations. - // Later logic synthesis will kill unused - // portions of the output domain. - - unsigned required_op_size = x_sz_revised + y_sz_revised; - - Wire *expanded_Y = module->addWire(NEW_ID, required_op_size); - + else /*signed multiplier */ CreateBoothSMult(module, x_sz_revised, y_sz_revised, required_op_size, expanded_A, // multiplicand expanded_B, // multiplier(scanned) expanded_Y // result (sized) ); - // now connect the expanded_Y with a tap to fill out sig Spec Y - - log("Adding reducer on output from %u to %u ", required_op_size, z_sz); - buf_name = "reducer_buf_"; - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, expanded_Y); - buf->setParam(ID::A_WIDTH, required_op_size); - buf->setParam(ID::Y_WIDTH, z_sz); // The real user width - buf->setParam(ID::A_SIGNED, true); - // wire in output Y - buf->setPort(ID::Y, SigSpec(Y)); - - // kill original multiplier - module->remove(cell); - booth_counter++; - continue; - } + module->remove(cell); + booth_counter++; + continue; } } } @@ -936,7 +834,7 @@ struct MultPassWorker { RTLIL::Wire *ha_op; BuildHa(ha_name, s_vec[n], c_vec[n - 1], ha_op, carry); - connect_sigSpecToWire(ha_op, SigSpec(result, n, 1)); + module->connect(ha_op, SigSpec(result, n, 1)); #ifdef DEBUG_CPA printf("CPA bit [%d] Cell %s IPs [%s] [%s] \n", n, ha_cell->name.c_str(), s_vec[n]->name.c_str(), @@ -971,11 +869,10 @@ struct MultPassWorker { RTLIL::Wire *ha_sum; RTLIL::Wire *ha_carry; BuildHa(ha_name, c_vec[n], carry, ha_sum, ha_carry); - if (n + 1 < (unsigned)GetSize(result)) - connect_sigSpecToWire(ha_sum, SigSpec(result, n + 1, 1)); + module->connect(ha_sum, SigSpec(result, n + 1, 1)); if (n + 2 < (unsigned)GetSize(result)) - connect_sigSpecToWire(ha_carry, SigSpec(result, n + 2, 1)); + module->connect(ha_carry, SigSpec(result, n + 2, 1)); } } // Step case @@ -1113,7 +1010,6 @@ struct MultPassWorker { { for (int y_ix = 0; y_ix < y_sz;) { std::string enc_name = "bur_enc_" + std::to_string(encoder_ix) + "_"; - log("Created booth encoder %s\n", enc_name.c_str()); std::string two_name = "two_int" + std::to_string(encoder_ix); two_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); @@ -1181,13 +1077,10 @@ struct MultPassWorker { if (need_padded_cell == true) { - log(" Creating padded encoder for unsigned\n"); - // make extra encoder cell // y_ix at y0, rest 0 std::string enc_name = "br_enc_pad" + std::to_string(encoder_ix) + "_"; - log("Created (padded) booth encoder %s\n", enc_name.c_str()); std::string two_name = "two_int" + std::to_string(encoder_ix); two_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); @@ -1518,14 +1411,11 @@ struct MultPassWorker { // instantiate the cpa RTLIL::Wire *cpa_carry[z_sz]; - if (x_sz + y_sz != z_sz) - log("Result of multiplier is incomplete with respect to domain of inputs\n"); - for (int cix = 0; cix < z_sz; cix++) { std::string cpa_cix_name = "cpa_carry_" + std::to_string(cix) + "_"; cpa_carry[cix] = module->addWire(new_id(cpa_cix_name, __LINE__, ""), 1); } - log(" Building cpa array for booth for output size %u\n", z_sz); + for (int cpa_ix = 0; cpa_ix < z_sz; cpa_ix++) { // The end case where we pass the last two summands @@ -1565,7 +1455,7 @@ struct MultPassWorker { RTLIL::Wire *op_wire = module->addWire(NEW_ID, 1); BuildHa(cpa_name, fa_sum_n[fa_row_count - 1][cpa_ix - offset + 2], ci_wire, op_wire, cpa_carry[cpa_ix - offset]); - connect_sigSpecToWire(op_wire, SigSpec(Z, cpa_ix, 1)); + module->connect(op_wire, SigSpec(Z, cpa_ix, 1)); } } @@ -1599,7 +1489,7 @@ struct MultPassWorker { }; struct MultPass : public Pass { - MultPass() : Pass("multpass", "Map $mul to booth multipliers") {} + MultPass() : Pass("booth", "Map $mul to booth multipliers") {} void execute(vector args, RTLIL::Design *design) override { (void)args; diff --git a/tests/techmap/booth_map_script.ys_ b/tests/techmap/booth_map_script.ys_ index 0f323bdd863..d2fe5d3f0a3 100644 --- a/tests/techmap/booth_map_script.ys_ +++ b/tests/techmap/booth_map_script.ys_ @@ -1 +1 @@ -multpass +booth From 1d92ea8001d7fde5aca8d8fe27c3c4839a97453a Mon Sep 17 00:00:00 2001 From: andyfox-rushc Date: Fri, 8 Sep 2023 16:16:24 -0700 Subject: [PATCH 022/173] Support for turning on mult pass from generic synth command --- techlibs/common/synth.cc | 70 +++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index 63395c36802..01dadae7163 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -17,17 +17,16 @@ * */ -#include "kernel/register.h" #include "kernel/celltypes.h" -#include "kernel/rtlil.h" #include "kernel/log.h" +#include "kernel/register.h" +#include "kernel/rtlil.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -struct SynthPass : public ScriptPass -{ - SynthPass() : ScriptPass("synth", "generic synthesis script") { } +struct SynthPass : public ScriptPass { + SynthPass() : ScriptPass("synth", "generic synthesis script") {} void help() override { @@ -60,6 +59,9 @@ struct SynthPass : public ScriptPass log(" -noabc\n"); log(" do not run abc (as if yosys was compiled without ABC support)\n"); log("\n"); + log(" -booth\n"); + log(" run the booth pass to convert $mul to Booth encoded multipliers"); + log("\n"); log(" -noalumacc\n"); log(" do not run 'alumacc' pass. i.e. keep arithmetic operators in\n"); log(" their direct form ($add, $sub, etc.).\n"); @@ -93,7 +95,8 @@ struct SynthPass : public ScriptPass } string top_module, fsm_opts, memory_opts, abc; - bool autotop, flatten, noalumacc, nofsm, noabc, noshare, flowmap; + bool autotop, flatten, noalumacc, nofsm, noabc, noshare, flowmap, mult; + int lut; void clear_flags() override @@ -110,6 +113,7 @@ struct SynthPass : public ScriptPass noabc = false; noshare = false; flowmap = false; + mult = false; abc = "abc"; } @@ -119,24 +123,23 @@ struct SynthPass : public ScriptPass clear_flags(); size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-top" && argidx+1 < args.size()) { + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-top" && argidx + 1 < args.size()) { top_module = args[++argidx]; continue; } - if (args[argidx] == "-encfile" && argidx+1 < args.size()) { + if (args[argidx] == "-encfile" && argidx + 1 < args.size()) { fsm_opts = " -encfile " + args[++argidx]; continue; } - if (args[argidx] == "-run" && argidx+1 < args.size()) { - size_t pos = args[argidx+1].find(':'); + if (args[argidx] == "-run" && argidx + 1 < args.size()) { + size_t pos = args[argidx + 1].find(':'); if (pos == std::string::npos) { run_from = args[++argidx]; run_to = args[argidx]; } else { run_from = args[++argidx].substr(0, pos); - run_to = args[argidx].substr(pos+1); + run_to = args[argidx].substr(pos + 1); } continue; } @@ -164,6 +167,11 @@ struct SynthPass : public ScriptPass noalumacc = true; continue; } + if (args[argidx] == "-mult") { + mult = true; + continue; + } + if (args[argidx] == "-nordff") { memory_opts += " -nordff"; continue; @@ -206,8 +214,7 @@ struct SynthPass : public ScriptPass void script() override { - if (check_label("begin")) - { + if (check_label("begin")) { if (help_mode) { run("hierarchy -check [-top | -auto-top]"); } else { @@ -221,8 +228,7 @@ struct SynthPass : public ScriptPass } } - if (check_label("coarse")) - { + if (check_label("coarse")) { run("proc"); if (help_mode || flatten) run("flatten", " (if -flatten)"); @@ -240,6 +246,8 @@ struct SynthPass : public ScriptPass run("techmap -map +/cmp2lut.v -map +/cmp2lcu.v", " (if -lut)"); else if (lut) run(stringf("techmap -map +/cmp2lut.v -map +/cmp2lcu.v -D LUT_WIDTH=%d", lut)); + if (mult) + run("booth"); if (!noalumacc) run("alumacc", " (unless -noalumacc)"); if (!noshare) @@ -249,50 +257,40 @@ struct SynthPass : public ScriptPass run("opt_clean"); } - if (check_label("fine")) - { + if (check_label("fine")) { run("opt -fast -full"); run("memory_map"); run("opt -full"); run("techmap"); - if (help_mode) - { + if (help_mode) { run("techmap -map +/gate2lut.v", "(if -noabc and -lut)"); run("clean; opt_lut", " (if -noabc and -lut)"); run("flowmap -maxlut K", " (if -flowmap and -lut)"); - } - else if (noabc && lut) - { + } else if (noabc && lut) { run(stringf("techmap -map +/gate2lut.v -D LUT_WIDTH=%d", lut)); run("clean; opt_lut"); - } - else if (flowmap) - { + } else if (flowmap) { run(stringf("flowmap -maxlut %d", lut)); } run("opt -fast"); if (!noabc && !flowmap) { - #ifdef YOSYS_ENABLE_ABC - if (help_mode) - { +#ifdef YOSYS_ENABLE_ABC + if (help_mode) { run(abc + " -fast", " (unless -noabc, unless -lut)"); run(abc + " -fast -lut k", "(unless -noabc, if -lut)"); - } - else - { + } else { if (lut) run(stringf("%s -fast -lut %d", abc.c_str(), lut)); else run(abc + " -fast"); } run("opt -fast", " (unless -noabc)"); - #endif +#endif } } - if (check_label("check")) - { + if (check_label("check")) { run("hierarchy -check"); run("stat"); run("check"); From 0fa412502cd19deef2d2972391e9b0e7c1726074 Mon Sep 17 00:00:00 2001 From: andyfox-rushc Date: Fri, 8 Sep 2023 16:44:59 -0700 Subject: [PATCH 023/173] mult -> booth in synth.cc, to turn on use synth -booth --- techlibs/common/synth.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index 01dadae7163..006a3c8dd84 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -95,7 +95,7 @@ struct SynthPass : public ScriptPass { } string top_module, fsm_opts, memory_opts, abc; - bool autotop, flatten, noalumacc, nofsm, noabc, noshare, flowmap, mult; + bool autotop, flatten, noalumacc, nofsm, noabc, noshare, flowmap, booth; int lut; @@ -113,7 +113,7 @@ struct SynthPass : public ScriptPass { noabc = false; noshare = false; flowmap = false; - mult = false; + booth = false; abc = "abc"; } @@ -167,8 +167,8 @@ struct SynthPass : public ScriptPass { noalumacc = true; continue; } - if (args[argidx] == "-mult") { - mult = true; + if (args[argidx] == "-booth") { + booth = true; continue; } @@ -246,7 +246,7 @@ struct SynthPass : public ScriptPass { run("techmap -map +/cmp2lut.v -map +/cmp2lcu.v", " (if -lut)"); else if (lut) run(stringf("techmap -map +/cmp2lut.v -map +/cmp2lcu.v -D LUT_WIDTH=%d", lut)); - if (mult) + if (booth) run("booth"); if (!noalumacc) run("alumacc", " (unless -noalumacc)"); From d77fb8150708f2e86bd6caa62424970cb3b71757 Mon Sep 17 00:00:00 2001 From: andyfox-rushc Date: Sun, 10 Sep 2023 12:45:36 -0700 Subject: [PATCH 024/173] 2d array -> 1d array in module generator --- passes/techmap/multpass.cc | 122 +++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 59 deletions(-) diff --git a/passes/techmap/multpass.cc b/passes/techmap/multpass.cc index c0e56f2ad61..5e8dcbc3bd8 100644 --- a/passes/techmap/multpass.cc +++ b/passes/techmap/multpass.cc @@ -1112,7 +1112,6 @@ struct MultPassWorker { /* Signed Multiplier */ - void CreateBoothSMult(RTLIL::Module *module, int x_sz, int y_sz, int z_sz, RTLIL::Wire *X, RTLIL::Wire *Y, RTLIL::Wire *Z) { // product unsigned enc_count = (y_sz / 2) + (((y_sz % 2) != 0) ? 1 : 0); @@ -1171,20 +1170,22 @@ struct MultPassWorker { cori_n_int[encoder_ix - 1]); } } + // Decoders and PP generation - RTLIL::Wire *PPij[enc_count][dec_count]; - RTLIL::Wire *nxj[enc_count][dec_count]; + RTLIL::Wire *PPij[enc_count * dec_count]; + RTLIL::Wire *nxj[enc_count * dec_count]; + for (int encoder_ix = 1; encoder_ix <= (int)enc_count; encoder_ix++) { for (int decoder_ix = 1; decoder_ix <= dec_count; decoder_ix++) { std::string ppij_name = "ppij_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; - PPij[encoder_ix - 1][decoder_ix - 1] = module->addWire(new_id(ppij_name, __LINE__, ""), 1); + PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = module->addWire(new_id(ppij_name, __LINE__, ""), 1); std::string nxj_name; if (decoder_ix == 1) nxj_name = "nxj_pre_dec" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; else nxj_name = "nxj_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; - nxj[encoder_ix - 1][decoder_ix - 1] = module->addWire(new_id(nxj_name, __LINE__, ""), 1); + nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = module->addWire(new_id(nxj_name, __LINE__, ""), 1); } } @@ -1202,7 +1203,7 @@ struct MultPassWorker { auto cell = module->addCell(new_id(pre_dec_name, __LINE__, ""), ID($_NOT_)); cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); cell->setPort(ID::A, negi_n_int[encoder_ix - 1]); - cell->setPort(ID::Y, nxj[encoder_ix - 1][0]); + cell->setPort(ID::Y, nxj[(encoder_ix - 1) * dec_count]); } for (int decoder_ix = 1; decoder_ix < dec_count; decoder_ix++) { @@ -1214,18 +1215,18 @@ struct MultPassWorker { std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; - BuildBr4d(dec_name, nxj[encoder_ix - 1][decoder_ix - 1], twoi_n_int[encoder_ix - 1], + BuildBr4d(dec_name, nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1], twoi_n_int[encoder_ix - 1], mk_wireFromSigSpec(SigSpec(X, decoder_ix - 1, 1)), negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], - PPij[encoder_ix - 1][decoder_ix - 1], nxj[encoder_ix - 1][decoder_ix]); + PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1], nxj[((encoder_ix - 1) * dec_count) + decoder_ix]); } // duplicate end for sign fix // applies to 9th decoder (xsz+1 decoder). std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(x_sz + 1) + "_"; RTLIL::Wire *unused_op = nullptr; - BuildBr4d(dec_name, nxj[encoder_ix - 1][dec_count - 1], twoi_n_int[encoder_ix - 1], + BuildBr4d(dec_name, nxj[((encoder_ix - 1) * dec_count) + dec_count - 1], twoi_n_int[encoder_ix - 1], mk_wireFromSigSpec(SigSpec(X, dec_count - 2, 1)), negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], - PPij[encoder_ix - 1][dec_count - 1], unused_op); + PPij[((encoder_ix - 1) * dec_count) + dec_count - 1], unused_op); } // @@ -1233,16 +1234,17 @@ struct MultPassWorker { // int fa_el_ix = 0; int fa_row_ix = 0; - RTLIL::Wire *fa_sum_n[fa_row_count][fa_count]; - RTLIL::Wire *fa_carry_n[fa_row_count][fa_count]; + // use 1 d arrays (2d cannot have variable sized indices) + RTLIL::Wire *fa_sum_n[fa_row_count * fa_count]; + RTLIL::Wire *fa_carry_n[fa_row_count * fa_count]; for (fa_row_ix = 0; fa_row_ix < fa_row_count; fa_row_ix++) { for (fa_el_ix = 0; fa_el_ix < fa_count; fa_el_ix++) { std::string fa_sum_name = "fa_sum_n_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_"; - fa_sum_n[fa_row_ix][fa_el_ix] = module->addWire(new_id(fa_sum_name, __LINE__, ""), 1); + fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] = module->addWire(new_id(fa_sum_name, __LINE__, ""), 1); std::string fa_carry_name = "fa_carry_n" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_"; - fa_carry_n[fa_row_ix][fa_el_ix] = module->addWire(new_id(fa_carry_name, __LINE__, ""), 1); + fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix] = module->addWire(new_id(fa_carry_name, __LINE__, ""), 1); } } @@ -1268,11 +1270,11 @@ struct MultPassWorker { bfa_name = "bfa_0_step_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; auto cell = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); cell->setParam(ID::WIDTH, 1); - cell->setPort(ID::A, PPij[0][fa_el_ix]); - cell->setPort(ID::B, PPij[1][fa_el_ix - 2]); - cell->setPort(ID::C, fa_carry_n[fa_row_ix][fa_el_ix - 1]); - cell->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); - cell->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + cell->setPort(ID::A, PPij[(0 * dec_count) + fa_el_ix]); + cell->setPort(ID::B, PPij[(1 * dec_count) + fa_el_ix - 2]); + cell->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); + cell->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); } // end 3 cells: x_sz+1.2.3 // @@ -1281,11 +1283,11 @@ struct MultPassWorker { bfa_name = "bfa_0_se_0" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); cell1->setParam(ID::WIDTH, 1); - cell1->setPort(ID::A, PPij[0][x_sz]); - cell1->setPort(ID::B, PPij[1][fa_el_ix - 2]); - cell1->setPort(ID::C, fa_carry_n[fa_row_ix][fa_el_ix - 1]); - cell1->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); - cell1->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + cell1->setPort(ID::A, PPij[(0 * dec_count) + x_sz]); + cell1->setPort(ID::B, PPij[(1 * dec_count) + fa_el_ix - 2]); + cell1->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); + cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); // exception:invert ppi fa_el_ix++; @@ -1295,7 +1297,7 @@ struct MultPassWorker { RTLIL::Wire *d08_inv = module->addWire(NEW_ID, 1); - cellinv1->setPort(ID::A, PPij[0][dec_count - 1]); + cellinv1->setPort(ID::A, PPij[(0 * dec_count) + dec_count - 1]); cellinv1->setPort(ID::Y, d08_inv); exc_inv_name = "bfa_0_exc_inv2_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; @@ -1303,7 +1305,7 @@ struct MultPassWorker { auto cellinv2 = module->addCell(new_id(exc_inv_name, __LINE__, ""), ID($_NOT_)); cellinv2->add_strpool_attribute(ID::src, cellinv2->get_strpool_attribute(ID::src)); RTLIL::Wire *d18_inv = module->addWire(NEW_ID, 1); - cellinv2->setPort(ID::A, PPij[1][dec_count - 1]); + cellinv2->setPort(ID::A, PPij[(1 * dec_count) + dec_count - 1]); cellinv2->setPort(ID::Y, d18_inv); bfa_name = "bfa_0_se_1_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; @@ -1312,9 +1314,9 @@ struct MultPassWorker { cell2->setParam(ID::WIDTH, 1); cell2->setPort(ID::A, d08_inv); cell2->setPort(ID::B, d18_inv); - cell2->setPort(ID::C, fa_carry_n[fa_row_ix][fa_el_ix - 1]); - cell2->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); - cell2->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); + cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); // sign extension fa_el_ix++; @@ -1323,9 +1325,9 @@ struct MultPassWorker { cell3->setParam(ID::WIDTH, 1); cell3->setPort(ID::A, State::S0); cell3->setPort(ID::B, State::S1); - cell3->setPort(ID::C, fa_carry_n[fa_row_ix][fa_el_ix - 1]); - cell3->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); - cell3->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + cell3->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); + cell3->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell3->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); } } @@ -1340,22 +1342,23 @@ struct MultPassWorker { std::to_string(fa_el_ix) + "_L"; auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); cell1->setParam(ID::WIDTH, 1); - cell1->setPort(ID::A, fa_sum_n[fa_row_ix - 1][2]); // from prior full adder row + cell1->setPort(ID::A, fa_sum_n[(fa_row_ix - 1) * fa_count + 2]); // from prior full adder row cell1->setPort(ID::B, State::S0); cell1->setPort(ID::C, cori_n_int[fa_row_ix]); - cell1->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); - cell1->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); fa_el_ix++; bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_base_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); cell2->setParam(ID::WIDTH, 1); - cell2->setPort(ID::A, fa_sum_n[fa_row_ix - 1][3]); // from prior full adder row + cell2->setPort(ID::A, + fa_sum_n[(fa_row_ix - 1) * fa_count + 3]); // from prior full adder row cell2->setPort(ID::B, State::S0); - cell2->setPort(ID::C, fa_carry_n[fa_row_ix][fa_el_ix - 1]); - cell2->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); - cell2->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); + cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); } else if (fa_el_ix >= 2 && fa_el_ix <= x_sz + 1) { @@ -1364,11 +1367,11 @@ struct MultPassWorker { std::to_string(fa_el_ix) + "_L"; auto cell = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); cell->setParam(ID::WIDTH, 1); - cell->setPort(ID::A, fa_sum_n[fa_row_ix - 1][fa_el_ix + 2]); - cell->setPort(ID::B, PPij[fa_row_ix + 1][fa_el_ix - 2]); - cell->setPort(ID::C, fa_carry_n[fa_row_ix][fa_el_ix - 1]); - cell->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); - cell->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + cell->setPort(ID::A, fa_sum_n[(fa_row_ix - 1) * fa_count + fa_el_ix + 2]); + cell->setPort(ID::B, PPij[(fa_row_ix + 1) * dec_count + fa_el_ix - 2]); + cell->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); + cell->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); } else if (fa_el_ix > x_sz + 1) { @@ -1379,18 +1382,18 @@ struct MultPassWorker { auto cellinv = module->addCell(new_id(se_inv_name, __LINE__, ""), ID($_NOT_)); cellinv->add_strpool_attribute(ID::src, cellinv->get_strpool_attribute(ID::src)); RTLIL::Wire *d_inv = module->addWire(NEW_ID, 1); - cellinv->setPort(ID::A, PPij[fa_row_ix + 1][dec_count - 1]); + cellinv->setPort(ID::A, PPij[((fa_row_ix + 1) * dec_count) + dec_count - 1]); cellinv->setPort(ID::Y, d_inv); bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_se_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); cell1->setParam(ID::WIDTH, 1); - cell1->setPort(ID::A, fa_carry_n[fa_row_ix - 1][fa_count - 1]); + cell1->setPort(ID::A, fa_carry_n[((fa_row_ix - 1) * fa_count) + fa_count - 1]); cell1->setPort(ID::B, d_inv); - cell1->setPort(ID::C, fa_carry_n[fa_row_ix][fa_el_ix - 1]); - cell1->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); - cell1->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + cell1->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); + cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); fa_el_ix++; // sign extension @@ -1400,9 +1403,9 @@ struct MultPassWorker { cell2->setParam(ID::WIDTH, 1); cell2->setPort(ID::A, State::S0); cell2->setPort(ID::B, State::S1); - cell2->setPort(ID::C, fa_carry_n[fa_row_ix][fa_el_ix - 1]); - cell2->setPort(ID::X, fa_carry_n[fa_row_ix][fa_el_ix]); - cell2->setPort(ID::Y, fa_sum_n[fa_row_ix][fa_el_ix]); + cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); + cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); } } } @@ -1428,7 +1431,7 @@ struct MultPassWorker { std::string buf_name = "pp_buf_" + std::to_string(cpa_ix) + "_" + "driven_by_fa_row_" + std::to_string(fa_row_ix) + "_"; auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, fa_sum_n[fa_row_ix][0]); + buf->setPort(ID::A, fa_sum_n[(fa_row_ix * fa_count) + 0]); buf->setParam(ID::A_WIDTH, 1); buf->setParam(ID::Y_WIDTH, 1); buf->setParam(ID::A_SIGNED, true); @@ -1437,7 +1440,7 @@ struct MultPassWorker { cpa_ix++; buf_name = "pp_buf_" + std::to_string(cpa_ix) + "_" + "driven_by_fa_row_" + std::to_string(fa_row_ix) + "_"; buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, fa_sum_n[fa_row_ix][1]); + buf->setPort(ID::A, fa_sum_n[(fa_row_ix * fa_count) + 1]); buf->setParam(ID::A_WIDTH, 1); buf->setParam(ID::Y_WIDTH, 1); buf->setParam(ID::A_SIGNED, true); @@ -1454,7 +1457,8 @@ struct MultPassWorker { ci_wire = cpa_carry[cpa_ix - offset - 1]; RTLIL::Wire *op_wire = module->addWire(NEW_ID, 1); - BuildHa(cpa_name, fa_sum_n[fa_row_count - 1][cpa_ix - offset + 2], ci_wire, op_wire, cpa_carry[cpa_ix - offset]); + BuildHa(cpa_name, fa_sum_n[(fa_row_count - 1) * fa_count + cpa_ix - offset + 2], ci_wire, op_wire, + cpa_carry[cpa_ix - offset]); module->connect(op_wire, SigSpec(Z, cpa_ix, 1)); } } @@ -1481,10 +1485,10 @@ struct MultPassWorker { nxj_o_int, cor_o_int, pp0_o_int, pp1_o_int); - join_wires_with_buffer(pp0_o_int, fa_sum_n[0][0]); - join_wires_with_buffer(pp1_o_int, fa_sum_n[0][1]); - join_wires_with_buffer(cor_o_int, fa_carry_n[0][1]); - join_wires_with_buffer(nxj_o_int, nxj[0][2]); + join_wires_with_buffer(pp0_o_int, fa_sum_n[(0 * fa_count) + 0]); + join_wires_with_buffer(pp1_o_int, fa_sum_n[(0 * fa_count) + 1]); + join_wires_with_buffer(cor_o_int, fa_carry_n[(0 * fa_count) + 1]); + join_wires_with_buffer(nxj_o_int, nxj[(0 * dec_count) + 2]); } }; From 8d4b6c2f69b5f6b2fb09289a535b74a20e7a7735 Mon Sep 17 00:00:00 2001 From: andyfox-rushc Date: Sun, 10 Sep 2023 13:31:47 -0700 Subject: [PATCH 025/173] Switched arrays for signed multiplier construction to heap --- passes/techmap/multpass.cc | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/passes/techmap/multpass.cc b/passes/techmap/multpass.cc index 5e8dcbc3bd8..00dcc6e2740 100644 --- a/passes/techmap/multpass.cc +++ b/passes/techmap/multpass.cc @@ -1124,10 +1124,10 @@ struct MultPassWorker { "Result of size %d. %d encoders %d decoders\n", x_sz, y_sz, z_sz, enc_count, dec_count); - RTLIL::Wire *negi_n_int[enc_count]; - RTLIL::Wire *twoi_n_int[enc_count]; - RTLIL::Wire *onei_n_int[enc_count]; - RTLIL::Wire *cori_n_int[enc_count]; + RTLIL::Wire **negi_n_int = new RTLIL::Wire *[enc_count]; + RTLIL::Wire **twoi_n_int = new RTLIL::Wire *[enc_count]; + RTLIL::Wire **onei_n_int = new RTLIL::Wire *[enc_count]; + RTLIL::Wire **cori_n_int = new RTLIL::Wire *[enc_count]; for (unsigned encoder_ix = 1; encoder_ix <= enc_count; encoder_ix++) { std::string enc_name = "enc_" + std::to_string(encoder_ix) + "_"; @@ -1172,8 +1172,8 @@ struct MultPassWorker { } // Decoders and PP generation - RTLIL::Wire *PPij[enc_count * dec_count]; - RTLIL::Wire *nxj[enc_count * dec_count]; + RTLIL::Wire **PPij = new RTLIL::Wire *[enc_count * dec_count]; + RTLIL::Wire **nxj = new RTLIL::Wire *[enc_count * dec_count]; for (int encoder_ix = 1; encoder_ix <= (int)enc_count; encoder_ix++) { for (int decoder_ix = 1; decoder_ix <= dec_count; decoder_ix++) { @@ -1235,8 +1235,8 @@ struct MultPassWorker { int fa_el_ix = 0; int fa_row_ix = 0; // use 1 d arrays (2d cannot have variable sized indices) - RTLIL::Wire *fa_sum_n[fa_row_count * fa_count]; - RTLIL::Wire *fa_carry_n[fa_row_count * fa_count]; + RTLIL::Wire **fa_sum_n = new RTLIL::Wire *[fa_row_count * fa_count]; + RTLIL::Wire **fa_carry_n = new RTLIL::Wire *[fa_row_count * fa_count]; for (fa_row_ix = 0; fa_row_ix < fa_row_count; fa_row_ix++) { for (fa_el_ix = 0; fa_el_ix < fa_count; fa_el_ix++) { @@ -1489,6 +1489,14 @@ struct MultPassWorker { join_wires_with_buffer(pp1_o_int, fa_sum_n[(0 * fa_count) + 1]); join_wires_with_buffer(cor_o_int, fa_carry_n[(0 * fa_count) + 1]); join_wires_with_buffer(nxj_o_int, nxj[(0 * dec_count) + 2]); + + delete[] negi_n_int; + delete[] twoi_n_int; + delete[] onei_n_int; + delete[] cori_n_int; + + delete[] fa_sum_n; + delete[] fa_carry_n; } }; From 1b5287af5908e71edd07d9de2d6872f3c2a389ed Mon Sep 17 00:00:00 2001 From: andyfox-rushc Date: Sun, 10 Sep 2023 14:20:30 -0700 Subject: [PATCH 026/173] cpa_carry array added to heap --- passes/techmap/multpass.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/passes/techmap/multpass.cc b/passes/techmap/multpass.cc index 00dcc6e2740..9e97fc6741e 100644 --- a/passes/techmap/multpass.cc +++ b/passes/techmap/multpass.cc @@ -1412,7 +1412,7 @@ struct MultPassWorker { } // instantiate the cpa - RTLIL::Wire *cpa_carry[z_sz]; + RTLIL::Wire **cpa_carry = new RTLIL::Wire *[z_sz]; for (int cix = 0; cix < z_sz; cix++) { std::string cpa_cix_name = "cpa_carry_" + std::to_string(cix) + "_"; @@ -1497,6 +1497,7 @@ struct MultPassWorker { delete[] fa_sum_n; delete[] fa_carry_n; + delete[] cpa_carry; } }; From bef7ffccc1103ac6e96934acf3bf8fd806df851a Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 11 Sep 2023 16:25:58 +0200 Subject: [PATCH 027/173] Update ABC to latest --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9474d37a19d..c3fc4145837 100644 --- a/Makefile +++ b/Makefile @@ -165,7 +165,7 @@ bumpversion: # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = bb64142 +ABCREV = 9537f39 ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) From a2c8e47295dbb93faeb2f949ce354c4faa919fc9 Mon Sep 17 00:00:00 2001 From: andyfox-rushc Date: Mon, 11 Sep 2023 11:39:13 -0700 Subject: [PATCH 028/173] multpass.cc -> booth.cc, added author/support contact info --- passes/techmap/Makefile.inc | 5 +---- passes/techmap/{multpass.cc => booth.cc} | 12 ++++++++---- 2 files changed, 9 insertions(+), 8 deletions(-) rename passes/techmap/{multpass.cc => booth.cc} (99%) diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 8b0b2aa23b7..fb003103d28 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -4,7 +4,7 @@ OBJS += passes/techmap/techmap.o OBJS += passes/techmap/simplemap.o OBJS += passes/techmap/dfflibmap.o OBJS += passes/techmap/maccmap.o -OBJS += passes/techmap/multpass.o +OBJS += passes/techmap/booth.o OBJS += passes/techmap/libparse.o ifeq ($(ENABLE_ABC),1) @@ -30,9 +30,6 @@ OBJS += passes/techmap/extract_reduce.o OBJS += passes/techmap/alumacc.o OBJS += passes/techmap/dffinit.o OBJS += passes/techmap/pmuxtree.o -OBJS += passes/techmap/bmuxmap.o -OBJS += passes/techmap/demuxmap.o -OBJS += passes/techmap/bwmuxmap.o OBJS += passes/techmap/muxcover.o OBJS += passes/techmap/aigmap.o OBJS += passes/techmap/tribuf.o diff --git a/passes/techmap/multpass.cc b/passes/techmap/booth.cc similarity index 99% rename from passes/techmap/multpass.cc rename to passes/techmap/booth.cc index 9e97fc6741e..21f16aec7a8 100644 --- a/passes/techmap/multpass.cc +++ b/passes/techmap/booth.cc @@ -1,6 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * + * Copyright (C) 2023 Andy Fox https://www.linkedin.com/in/awfox/ * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,8 +18,8 @@ */ /* - MultPass - -------- + Booth Pass + ---------- Replace $mul with booth encoded multipliers. Two different architectures used for signed/unsigned. @@ -31,13 +32,13 @@ http://i.stanford.edu/pub/cstr/reports/csl/tr/94/617/CSL-TR-94-617.pdf How to use: - Add multpass to your yosys script eg: + Add booth pass to your yosys script eg: read_verilog smultiply5_rtl.v opt wreduce opt - multpass + booth alumacc maccmap opt @@ -46,6 +47,9 @@ abc -liberty NangateOpenCellLibrary_typical.lib stat -liberty NangateOpenCellLibrary_typical.lib write_verilog -norename booth_final.v + +or in generic synthesis call with -booth argument: +synth -top my_design -booth */ #include "kernel/sigtools.h" From eccc0ae6db50effc7f42d69038918483d6888089 Mon Sep 17 00:00:00 2001 From: andyfox-rushc Date: Mon, 11 Sep 2023 12:14:12 -0700 Subject: [PATCH 029/173] Based passes/techmap/Makefile.inc changes on latest in yosys --- passes/techmap/Makefile.inc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index fb003103d28..97d8b76f3b8 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -30,6 +30,9 @@ OBJS += passes/techmap/extract_reduce.o OBJS += passes/techmap/alumacc.o OBJS += passes/techmap/dffinit.o OBJS += passes/techmap/pmuxtree.o +OBJS += passes/techmap/bmuxmap.o +OBJS += passes/techmap/demuxmap.o +OBJS += passes/techmap/bwmuxmap.o OBJS += passes/techmap/muxcover.o OBJS += passes/techmap/aigmap.o OBJS += passes/techmap/tribuf.o From e4fe522767c3ddfeb90c2f4091890cb45584e0e9 Mon Sep 17 00:00:00 2001 From: andyfox-rushc Date: Mon, 11 Sep 2023 13:00:11 -0700 Subject: [PATCH 030/173] MultPassWorker -> BoothPassWorker --- passes/techmap/booth.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index 21f16aec7a8..e749168522d 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -58,13 +58,13 @@ synth -top my_design -booth USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -struct MultPassWorker { +struct BoothPassWorker { RTLIL::Module *module; SigMap sigmap; int booth_counter; - MultPassWorker(RTLIL::Module *module) : module(module), sigmap(module) { booth_counter = 0; } + BoothPassWorker(RTLIL::Module *module) : module(module), sigmap(module) { booth_counter = 0; } // Helper routines for building architecture subcomponents @@ -1505,15 +1505,16 @@ struct MultPassWorker { } }; -struct MultPass : public Pass { - MultPass() : Pass("booth", "Map $mul to booth multipliers") {} +struct BoothPass : public Pass { + BoothPass() : Pass("booth", "Map $mul to booth multipliers") {} void execute(vector args, RTLIL::Design *design) override { (void)args; - log_header(design, "Executing multpass. Generating Booth Multiplier structures for signed/unsigned multipliers of 4 bits or more\n"); + log_header(design, + "Executing booth pass. Generating Booth Multiplier structures for signed/unsigned multipliers of 4 bits or more\n"); for (auto mod : design->selected_modules()) if (!mod->has_processes_warn()) { - MultPassWorker worker(mod); + BoothPassWorker worker(mod); worker.run(); log_header(design, "Created %d booth multipliers.\n", worker.booth_counter); } From 7b134c2a8cd63222fd005315f1a07c20e97fd546 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 12 Sep 2023 11:56:15 +0200 Subject: [PATCH 031/173] verific - respect order of read and write for rams --- frontends/verific/verific.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index b0d789d8fa3..4f4fbcb746e 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2951,6 +2951,9 @@ struct VerificPass : public Pass { RuntimeFlags::SetVar("db_infer_wide_operators", 1); RuntimeFlags::SetVar("db_infer_set_reset_registers", 0); + // Properly respect order of read and write for rams + RuntimeFlags::SetVar("db_change_inplace_ram_blocking_write_before_read", 1); + RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); RuntimeFlags::SetVar("veri_allow_any_ram_in_loop", 1); From cbc4ec8178ddc67e397ccd0800048a26d1f41451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 12 Sep 2023 14:54:03 +0200 Subject: [PATCH 032/173] mem: Fix index confusion in write port merging Fix mistaking the read-port and write-port indices for each other when we are adding the partial transparency emulation to be able to merge two write ports. --- kernel/mem.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/mem.cc b/kernel/mem.cc index 628f6210499..269a476a125 100644 --- a/kernel/mem.cc +++ b/kernel/mem.cc @@ -1252,12 +1252,12 @@ void Mem::prepare_wr_merge(int idx1, int idx2, FfInitVals *initvals) { // If transparent with only one, emulate it, and remove the collision-X // flag that emulate_transparency will set (to align with the other port). if (rport.transparency_mask[idx1]) { - emulate_transparency(i, idx1, initvals); + emulate_transparency(idx1, i, initvals); rport.collision_x_mask[idx1] = false; continue; } if (rport.transparency_mask[idx2]) { - emulate_transparency(i, idx2, initvals); + emulate_transparency(idx2, i, initvals); rport.collision_x_mask[idx2] = false; continue; } From 98b9459535681a0c3a4739f208a32dfc50c9bfea Mon Sep 17 00:00:00 2001 From: gatecat Date: Tue, 12 Sep 2023 18:12:07 +0200 Subject: [PATCH 033/173] fmt: Fix C++ string assertion when buf is empty Signed-off-by: gatecat --- kernel/fmt.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/fmt.cc b/kernel/fmt.cc index 69bdbb013b0..965e58ebce4 100644 --- a/kernel/fmt.cc +++ b/kernel/fmt.cc @@ -740,7 +740,7 @@ std::string Fmt::render() const log_assert(part.width == 0 || part.padding != '\0'); if (part.justify == FmtPart::RIGHT && buf.size() < part.width) { size_t pad_width = part.width - buf.size(); - if (part.padding == '0' && (buf.front() == '+' || buf.front() == '-')) { + if (part.padding == '0' && (!buf.empty() && (buf.front() == '+' || buf.front() == '-'))) { str += buf.front(); buf.erase(0, 1); } From 08f79d111e9be151e9ede91491a6e2c2080ad847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Sat, 9 Sep 2023 22:32:51 +0200 Subject: [PATCH 034/173] ci: Enable extra libstdc++ assertions --- .github/workflows/test-linux.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-linux.yml b/.github/workflows/test-linux.yml index eee556794af..a16481726d3 100644 --- a/.github/workflows/test-linux.yml +++ b/.github/workflows/test-linux.yml @@ -43,6 +43,7 @@ jobs: sudo apt-get install $CC $CXX echo "CC=$CC" >> $GITHUB_ENV echo "CXX=$CXX" >> $GITHUB_ENV + echo "CXXFLAGS=-Wp,-D_GLIBCXX_ASSERTIONS" >> $GITHUB_ENV env: CC: ${{ matrix.compiler }} From 9e004426e0783d5bbbe846be54b8266451cd5f7f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 13 Sep 2023 00:14:55 +0000 Subject: [PATCH 035/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c3fc4145837..0c79636497f 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+6 +YOSYS_VER := 0.33+21 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 54050a8c16dbd9bf8bf17db08201fca23a3b4723 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 7 Jun 2023 10:20:16 +0200 Subject: [PATCH 036/173] Basic support for tag primitives --- frontends/verific/verific.cc | 32 +++++++++++++++ kernel/celltypes.h | 4 ++ kernel/constids.inc | 1 + kernel/rtlil.cc | 77 ++++++++++++++++++++++++++++++++++++ kernel/rtlil.h | 5 +++ techlibs/common/simlib.v | 57 ++++++++++++++++++++++++++ 6 files changed, 176 insertions(+) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 4f4fbcb746e..6000df9e628 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1103,6 +1103,38 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr return true; } + if (inst->Type() == OPER_YOSYSHQ_SET_TAG) + { + RTLIL::SigSpec sig_expr = operatorInport(inst, "expr"); + RTLIL::SigSpec sig_set_mask = operatorInport(inst, "set_mask"); + RTLIL::SigSpec sig_clr_mask = operatorInport(inst, "clr_mask"); + RTLIL::SigSpec sig_o = operatorOutput(inst); + std::string tag = inst->GetAtt("tag") ? inst->GetAttValue("tag") : ""; + module->connect(sig_o, module->SetTag(new_verific_id(inst), tag, sig_expr, sig_set_mask, sig_clr_mask)); + return true; + } + if (inst->Type() == OPER_YOSYSHQ_GET_TAG) + { + std::string tag = inst->GetAtt("tag") ? inst->GetAttValue("tag") : ""; + module->connect(operatorOutput(inst),module->GetTag(new_verific_id(inst), tag, operatorInput(inst))); + return true; + } + if (inst->Type() == OPER_YOSYSHQ_OVERWRITE_TAG) + { + RTLIL::SigSpec sig_signal = operatorInport(inst, "signal"); + RTLIL::SigSpec sig_set_mask = operatorInport(inst, "set_mask"); + RTLIL::SigSpec sig_clr_mask = operatorInport(inst, "clr_mask"); + std::string tag = inst->GetAtt("tag") ? inst->GetAttValue("tag") : ""; + module->addOverwriteTag(new_verific_id(inst), tag, sig_signal, sig_set_mask, sig_clr_mask); + return true; + } + if (inst->Type() == OPER_YOSYSHQ_ORIGINAL_TAG) + { + std::string tag = inst->GetAtt("tag") ? inst->GetAttValue("tag") : ""; + module->connect(operatorOutput(inst),module->OriginalTag(new_verific_id(inst), tag, operatorInput(inst))); + return true; + } + #undef IN #undef IN1 #undef IN2 diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 4a0621a7386..573ea0b4276 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -102,6 +102,10 @@ struct CellTypes setup_type(ID($specify3), {ID::EN, ID::SRC, ID::DST, ID::DAT}, pool(), true); setup_type(ID($specrule), {ID::EN_SRC, ID::EN_DST, ID::SRC, ID::DST}, pool(), true); setup_type(ID($print), {ID::EN, ID::ARGS, ID::TRG}, pool()); + setup_type(ID($set_tag), {ID::A, ID::SET, ID::CLR}, {ID::Y}); + setup_type(ID($get_tag), {ID::A}, {ID::Y}); + setup_type(ID($overwrite_tag), {ID::A, ID::SET, ID::CLR}, pool()); + setup_type(ID($original_tag), {ID::A}, {ID::Y}); } void setup_internals_eval() diff --git a/kernel/constids.inc b/kernel/constids.inc index 08b0ecdc2b4..93101282a0b 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -208,6 +208,7 @@ X(syn_romstyle) X(S_WIDTH) X(T) X(TABLE) +X(TAG) X(techmap_autopurge) X(_TECHMAP_BITS_CONNMAP_) X(_TECHMAP_CELLNAME_) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 7a59c526275..2563aa21aa6 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -1828,6 +1828,33 @@ namespace { ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_))) { port(ID::E,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; } + if (cell->type.in(ID($set_tag))) { + param(ID::WIDTH); + param(ID::TAG); + port(ID::A, param(ID::WIDTH)); + port(ID::SET, param(ID::WIDTH)); + port(ID::CLR, param(ID::WIDTH)); + port(ID::Y, param(ID::WIDTH)); + check_expected(); + return; + } + if (cell->type.in(ID($get_tag),ID($original_tag))) { + param(ID::WIDTH); + param(ID::TAG); + port(ID::A, param(ID::WIDTH)); + port(ID::Y, param(ID::WIDTH)); + check_expected(); + return; + } + if (cell->type.in(ID($overwrite_tag))) { + param(ID::WIDTH); + param(ID::TAG); + port(ID::A, param(ID::WIDTH)); + port(ID::SET, param(ID::WIDTH)); + port(ID::CLR, param(ID::WIDTH)); + check_expected(); + return; + } error(__LINE__); } }; @@ -3246,6 +3273,56 @@ RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name, const std::string return sig; } +RTLIL::SigSpec RTLIL::Module::SetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src) +{ + RTLIL::SigSpec sig = addWire(NEW_ID, sig_e.size()); + Cell *cell = addCell(name, ID($set_tag)); + cell->parameters[ID::WIDTH] = sig_e.size(); + cell->parameters[ID::TAG] = tag; + cell->setPort(ID::A, sig_e); + cell->setPort(ID::SET, sig_s); + cell->setPort(ID::CLR, sig_c); + cell->setPort(ID::Y, sig); + cell->set_src_attribute(src); + return sig; +} + +RTLIL::SigSpec RTLIL::Module::GetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const std::string &src) +{ + RTLIL::SigSpec sig = addWire(NEW_ID, sig_e.size()); + Cell *cell = addCell(name, ID($get_tag)); + cell->parameters[ID::WIDTH] = sig_e.size(); + cell->parameters[ID::TAG] = tag; + cell->setPort(ID::A, sig_e); + cell->setPort(ID::Y, sig); + cell->set_src_attribute(src); + return sig; +} + +RTLIL::Cell* RTLIL::Module::addOverwriteTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src) +{ + RTLIL::Cell *cell = addCell(name, ID($overwrite_tag)); + cell->parameters[ID::WIDTH] = sig_e.size(); + cell->parameters[ID::TAG] = tag; + cell->setPort(ID::A, sig_e); + cell->setPort(ID::SET, sig_s); + cell->setPort(ID::CLR, sig_c); + cell->set_src_attribute(src); + return cell; +} + +RTLIL::SigSpec RTLIL::Module::OriginalTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const std::string &src) +{ + RTLIL::SigSpec sig = addWire(NEW_ID, sig_e.size()); + Cell *cell = addCell(name, ID($original_tag)); + cell->parameters[ID::WIDTH] = sig_e.size(); + cell->parameters[ID::TAG] = tag; + cell->setPort(ID::A, sig_e); + cell->setPort(ID::Y, sig); + cell->set_src_attribute(src); + return sig; +} + RTLIL::Wire::Wire() { static unsigned int hashidx_count = 123456789; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index a69ce480baf..d29150d32ce 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1465,6 +1465,11 @@ struct RTLIL::Module : public RTLIL::AttrObject RTLIL::SigSpec Allseq (RTLIL::IdString name, int width = 1, const std::string &src = ""); RTLIL::SigSpec Initstate (RTLIL::IdString name, const std::string &src = ""); + RTLIL::SigSpec SetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = ""); + RTLIL::SigSpec GetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const std::string &src = ""); + RTLIL::Cell* addOverwriteTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = ""); + RTLIL::SigSpec OriginalTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const std::string &src = ""); + #ifdef WITH_PYTHON static std::map *get_all_modules(void); #endif diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index cdb6e02e762..429e95b2853 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -2671,3 +2671,60 @@ endmodule `endif // -------------------------------------------------------- + +module \$set_tag (A, SET, CLR, Y); + +parameter TAG = ""; +parameter WIDTH = 0; + +input [WIDTH-1:0] A; +input [WIDTH-1:0] SET; +input [WIDTH-1:0] CLR; +output [WIDTH-1:0] Y; + +assign Y = A; + +endmodule + +// -------------------------------------------------------- + +module \$get_tag (A, Y); + +parameter TAG = ""; +parameter WIDTH = 0; + +input [WIDTH-1:0] A; +output [WIDTH-1:0] Y; + +assign Y = A; + +endmodule + +// -------------------------------------------------------- + +module \$overwrite_tag (A, SET, CLR); + +parameter TAG = ""; +parameter WIDTH = 0; + +input [WIDTH-1:0] A; +input [WIDTH-1:0] SET; +input [WIDTH-1:0] CLR; + +endmodule + +// -------------------------------------------------------- + +module \$original_tag (A, Y); + +parameter TAG = ""; +parameter WIDTH = 0; + +input [WIDTH-1:0] A; +output [WIDTH-1:0] Y; + +assign Y = A; + +endmodule + +// -------------------------------------------------------- From 9c255c98b17a8c5258666edf2d323818431def9d Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 21 Jun 2023 17:09:28 +0200 Subject: [PATCH 037/173] unescape string tag attribute --- frontends/verific/verific.cc | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 6000df9e628..be417c9dc63 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -251,6 +251,14 @@ static const RTLIL::Const verific_const(const char *value, bool allow_string = t return c; } +static const std::string verific_unescape(const char *value) +{ + std::string val = std::string(value); + if (val.size()>1 && val[0]=='\"' && val.back()=='\"') + return val.substr(1,val.size()-2); + return value; +} + void VerificImporter::import_attributes(dict &attributes, DesignObj *obj, Netlist *nl) { MapIter mi; @@ -1109,13 +1117,13 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr RTLIL::SigSpec sig_set_mask = operatorInport(inst, "set_mask"); RTLIL::SigSpec sig_clr_mask = operatorInport(inst, "clr_mask"); RTLIL::SigSpec sig_o = operatorOutput(inst); - std::string tag = inst->GetAtt("tag") ? inst->GetAttValue("tag") : ""; + std::string tag = inst->GetAtt("tag") ? verific_unescape(inst->GetAttValue("tag")) : ""; module->connect(sig_o, module->SetTag(new_verific_id(inst), tag, sig_expr, sig_set_mask, sig_clr_mask)); return true; } if (inst->Type() == OPER_YOSYSHQ_GET_TAG) { - std::string tag = inst->GetAtt("tag") ? inst->GetAttValue("tag") : ""; + std::string tag = inst->GetAtt("tag") ? verific_unescape(inst->GetAttValue("tag")) : ""; module->connect(operatorOutput(inst),module->GetTag(new_verific_id(inst), tag, operatorInput(inst))); return true; } @@ -1124,13 +1132,13 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr RTLIL::SigSpec sig_signal = operatorInport(inst, "signal"); RTLIL::SigSpec sig_set_mask = operatorInport(inst, "set_mask"); RTLIL::SigSpec sig_clr_mask = operatorInport(inst, "clr_mask"); - std::string tag = inst->GetAtt("tag") ? inst->GetAttValue("tag") : ""; + std::string tag = inst->GetAtt("tag") ? verific_unescape(inst->GetAttValue("tag")) : ""; module->addOverwriteTag(new_verific_id(inst), tag, sig_signal, sig_set_mask, sig_clr_mask); return true; } if (inst->Type() == OPER_YOSYSHQ_ORIGINAL_TAG) { - std::string tag = inst->GetAtt("tag") ? inst->GetAttValue("tag") : ""; + std::string tag = inst->GetAtt("tag") ? verific_unescape(inst->GetAttValue("tag")) : ""; module->connect(operatorOutput(inst),module->OriginalTag(new_verific_id(inst), tag, operatorInput(inst))); return true; } From 27ac91270991ad7c2304e5f90a5c1001c2f08ec1 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 24 Aug 2023 11:55:30 +0200 Subject: [PATCH 038/173] Support import of $future_ff --- frontends/verific/verific.cc | 5 +++++ kernel/celltypes.h | 1 + kernel/rtlil.cc | 18 ++++++++++++++++++ kernel/rtlil.h | 1 + techlibs/common/simlib.v | 13 +++++++++++++ 5 files changed, 38 insertions(+) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index be417c9dc63..d30b46082e1 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1142,6 +1142,11 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr module->connect(operatorOutput(inst),module->OriginalTag(new_verific_id(inst), tag, operatorInput(inst))); return true; } + if (inst->Type() == OPER_YOSYSHQ_FUTURE_FF) + { + module->connect(operatorOutput(inst),module->FutureFF(new_verific_id(inst), operatorInput(inst))); + return true; + } #undef IN #undef IN1 diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 573ea0b4276..cad505d9afd 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -106,6 +106,7 @@ struct CellTypes setup_type(ID($get_tag), {ID::A}, {ID::Y}); setup_type(ID($overwrite_tag), {ID::A, ID::SET, ID::CLR}, pool()); setup_type(ID($original_tag), {ID::A}, {ID::Y}); + setup_type(ID($future_ff), {ID::A}, {ID::Y}); } void setup_internals_eval() diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 2563aa21aa6..7d257714460 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -1855,6 +1855,13 @@ namespace { check_expected(); return; } + if (cell->type.in(ID($future_ff))) { + param(ID::WIDTH); + port(ID::A, param(ID::WIDTH)); + port(ID::Y, param(ID::WIDTH)); + check_expected(); + return; + } error(__LINE__); } }; @@ -3323,6 +3330,17 @@ RTLIL::SigSpec RTLIL::Module::OriginalTag(RTLIL::IdString name, const std::strin return sig; } +RTLIL::SigSpec RTLIL::Module::FutureFF(RTLIL::IdString name, const RTLIL::SigSpec &sig_e, const std::string &src) +{ + RTLIL::SigSpec sig = addWire(NEW_ID, sig_e.size()); + Cell *cell = addCell(name, ID($future_ff)); + cell->parameters[ID::WIDTH] = sig_e.size(); + cell->setPort(ID::A, sig_e); + cell->setPort(ID::Y, sig); + cell->set_src_attribute(src); + return sig; +} + RTLIL::Wire::Wire() { static unsigned int hashidx_count = 123456789; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index d29150d32ce..012865a75c6 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1469,6 +1469,7 @@ struct RTLIL::Module : public RTLIL::AttrObject RTLIL::SigSpec GetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const std::string &src = ""); RTLIL::Cell* addOverwriteTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = ""); RTLIL::SigSpec OriginalTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const std::string &src = ""); + RTLIL::SigSpec FutureFF (RTLIL::IdString name, const RTLIL::SigSpec &sig_e, const std::string &src = ""); #ifdef WITH_PYTHON static std::map *get_all_modules(void); diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 429e95b2853..fd804786fd8 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -2728,3 +2728,16 @@ assign Y = A; endmodule // -------------------------------------------------------- + +module \$future_ff (A, Y); + +parameter WIDTH = 0; + +input [WIDTH-1:0] A; +output [WIDTH-1:0] Y; + +assign Y = A; + +endmodule + +// -------------------------------------------------------- From 7a0c37b62d5fadf1ae95afbc9daced71a44fc724 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Thu, 13 Jul 2023 14:04:40 +0200 Subject: [PATCH 039/173] Initial dft_tag implementation This is still missing a mode to rewrite $overwrite_tag and $original_tag by injecting $set_tag and $get_tag in the right places. It's also missing bit-precise propagation models for shifts and arithmetic and requires the design to be flattened. --- passes/cmds/Makefile.inc | 1 + passes/cmds/dft_tag.cc | 932 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 933 insertions(+) create mode 100644 passes/cmds/dft_tag.cc diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc index 29b3a1132ad..f3cd9b9509b 100644 --- a/passes/cmds/Makefile.inc +++ b/passes/cmds/Makefile.inc @@ -46,3 +46,4 @@ OBJS += passes/cmds/printattrs.o OBJS += passes/cmds/sta.o OBJS += passes/cmds/clean_zerowidth.o OBJS += passes/cmds/xprop.o +OBJS += passes/cmds/dft_tag.o diff --git a/passes/cmds/dft_tag.cc b/passes/cmds/dft_tag.cc new file mode 100644 index 00000000000..24fdf9714c8 --- /dev/null +++ b/passes/cmds/dft_tag.cc @@ -0,0 +1,932 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2022 Jannis Harder + * + * 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/celltypes.h" +#include "kernel/ff.h" +#include "kernel/modtools.h" +#include "kernel/sigtools.h" +#include "kernel/yosys.h" +#include + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct DftTagOptions { + bool tag_public; +}; + +struct DftTagWorker { + Module *module; + DftTagOptions options; + ModWalker modwalker; + SigMap &sigmap; + FfInitVals initvals; + + struct tag_set { + int index = 0; + + tag_set(int index = 0) : index(index) {} + + bool operator<(const tag_set &other) const { return index < other.index; } + bool operator==(const tag_set &other) const { return index == other.index; } + + unsigned int hash() const { return hash_ops::hash(index); } + + bool empty() const { return index == 0; } + }; + + idict> tag_sets; + + pool tmp_tag_set; + dict, tag_set> tag_set_union_cache; + + dict tagged_signals; + + dict> tag_groups; + dict group_of_tag; + pool all_tags; + + pool pending_cells; + std::deque pending_cell_queue; + + dict, SigBit> tag_signals; + + // Uses SigSpec instead of SigBit so we can use coarse grained cells to combine the individual tags + dict, SigSpec> tag_group_signals; + + pool warned_cells; + + DftTagWorker(Module *module, DftTagOptions options) : + module(module), options(options), modwalker(module->design), sigmap(modwalker.sigmap) + { + modwalker.setup(module); + initvals.set(&modwalker.sigmap, module); + tag_sets(tmp_tag_set); + } + + const pool &tag_pool(tag_set set) { return tag_sets[set.index]; } + + tag_set singleton(IdString tag) + { + tmp_tag_set.clear(); + tmp_tag_set.emplace(tag); + return tag_sets(tmp_tag_set); + } + + tag_set merge(tag_set a, tag_set b) + { + if (b < a) + std::swap(a, b); + if (a.empty() || a == b) + return b; + auto found = tag_set_union_cache.find(std::make_pair(a, b)); + if (found == tag_set_union_cache.end()) { + tmp_tag_set.clear(); + auto &a_tags = tag_pool(a); + auto &b_tags = tag_pool(b); + tmp_tag_set.insert(a_tags.begin(), a_tags.end()); + tmp_tag_set.insert(b_tags.begin(), b_tags.end()); + tag_set result = tag_sets(tmp_tag_set); + tag_set_union_cache.emplace(std::make_pair(a, b), result); + return result; + } + return found->second; + } + + tag_set tags(SigBit bit) + { + sigmap.apply(bit); + auto found = tagged_signals.find(bit); + if (found != tagged_signals.end()) + return found->second; + return tag_set(); + } + + tag_set tags(SigSpec sig) + { + tag_set result; + for (auto bit : sig) + result = merge(result, tags(bit)); + return result; + } + + tag_set tags(Cell *cell) + { + tag_set result; + for (auto &conn : cell->connections()) { + if (cell->input(conn.first)) + result = merge(result, tags(conn.second)); + } + return result; + } + + void add_tags(SigBit bit, tag_set new_tags) + { + sigmap.apply(bit); + auto &tags = tagged_signals[bit]; + tag_set merged_tags = merge(tags, new_tags); + if (merged_tags == tags) + return; + tags = merged_tags; + auto it = modwalker.signal_consumers.find(bit); + if (it == modwalker.signal_consumers.end()) + return; + for (auto &consumer : it->second) + if (pending_cells.insert(consumer.cell).second) + pending_cell_queue.push_back(consumer.cell); + } + + void add_tags(SigSpec sig, tag_set new_tags) + { + for (auto bit : sigmap(sig)) + add_tags(bit, new_tags); + } + + void add_tags(Cell *cell, tag_set new_tags) + { + for (auto &conn : cell->connections()) + if (cell->output(conn.first)) + add_tags(conn.second, new_tags); + } + + void forward_tags(SigSpec dst, SigSpec src) + { + log_assert(GetSize(dst) == GetSize(src)); + for (int i = 0; i < GetSize(dst); i++) + add_tags(dst[i], tags(src[i])); + } + + void propagate_tags() + { + for (auto cell : module->cells()) { + if (cell->type == ID($set_tag)) { + pending_cells.insert(cell); + pending_cell_queue.push_back(cell); + } + } + + while (!pending_cell_queue.empty()) { + Cell *cell = pending_cell_queue.front(); + pending_cell_queue.pop_front(); + pending_cells.erase(cell); + + propagate_tags(cell); + } + } + + SigBit tag_signal(IdString tag, SigBit bit) + { + sigmap.apply(bit); + if (!bit.is_wire()) + return State::S0; // Constant value - no tags + + auto found = tag_signals.find(std::make_pair(tag, bit)); + if (found != tag_signals.end()) + return found->second; + + if (!tag_pool(tags(bit)).count(tag)) + return State::S0; // Statically known to not have this tag + + // TODO handle module inputs + auto drivers = modwalker.signal_drivers.find(bit); + if (drivers == modwalker.signal_drivers.end() || drivers->second.empty()) + return State::S0; // No driver - no tags + + log_assert(drivers->second.size() == 1); + auto driver = *drivers->second.begin(); + + emit_tag_signals(tag, driver.cell); + + found = tag_signals.find(std::make_pair(tag, bit)); + log_assert(found != tag_signals.end()); + return found->second; + } + + SigSpec tag_signal(IdString tag, SigSpec sig) + { + SigSpec result; + for (auto bit : sig) + result.append(tag_signal(tag, bit)); + return result; + } + + SigSpec tag_group_signal(IdString tag_group, SigSpec sig) + { + sigmap.apply(sig); + if (sig.is_fully_const() || tag_groups.count(tag_group) == 0) + return Const(0, GetSize(sig)); + + auto found = tag_group_signals.find(std::make_pair(tag_group, sig)); + if (found != tag_group_signals.end()) + return found->second; + + SigSpec combined; + + for (auto &tag : tag_groups[tag_group]) { + auto tag_sig = tag_signal(tag, sig); + + if (!GetSize(combined)) + combined = tag_sig; + else + combined = autoOr(NEW_ID, combined, tag_sig); + } + + if (!GetSize(combined)) + combined = Const(0, GetSize(sig)); + + tag_group_signals.emplace(std::make_pair(tag_group, sig), combined); + return combined; + } + + void emit_tag_signal(IdString tag, SigBit bit, SigBit tag_bit) + { + sigmap.apply(bit); + sigmap.apply(tag_bit); + + if (!tag_pool(tags(bit)).count(tag)) + return; + + auto key = std::make_pair(tag, bit); + auto found = tag_signals.find(key); + if (found != tag_signals.end()) { + module->connect(found->second, tag_bit); + return; + } + tag_signals.emplace(key, tag_bit); + } + + void emit_tag_signal(IdString tag, SigSpec sig, SigSpec tag_sig) + { + log_assert(GetSize(sig) == GetSize(tag_sig)); + for (int i = 0; i < GetSize(sig); i++) + emit_tag_signal(tag, sig[i], tag_sig[i]); + } + + void emit_tag_signals(IdString tag, Cell *cell) + { + if (!pending_cells.insert(cell).second) { + // We have a cycle, emit placeholder wires which will be connected + // when the outer call for this tag/cell returns + for (auto &conn : cell->connections()) + if (cell->output(conn.first)) + emit_tag_signal(tag, conn.second, module->addWire(NEW_ID, GetSize(conn.second))); + + return; + } + + process_cell(tag, cell); + + pending_cells.erase(cell); + } + + void propagate_tags(Cell *cell) + { + if (cell->type == ID($set_tag)) { + IdString tag = stringf("\\%s", cell->getParam(ID::TAG).decode_string().c_str()); + if (all_tags.insert(tag).second) { + auto group_sep = tag.str().find(':'); + IdString tag_group = group_sep != std::string::npos ? tag.str().substr(0, group_sep) : tag; + tag_groups[tag_group].insert(tag); + group_of_tag[tag] = tag_group; + } + + auto &sig_y = cell->getPort(ID::Y); + auto &sig_a = cell->getPort(ID::A); + // TODO handle constant set/clr masks + add_tags(sig_y, singleton(tag)); + forward_tags(sig_y, sig_a); + return; + } + + if (cell->type == ID($get_tag)) { + return; + } + + if (cell->type.in(ID($not), ID($pos))) { + auto &sig_y = cell->getPort(ID::Y); + auto sig_a = cell->getPort(ID::A); + if (cell->type.in(ID($not), ID($or))) { + sig_a.extend_u0(GetSize(sig_y), cell->getParam(ID::A_SIGNED).as_bool()); + } + forward_tags(sig_y, sig_a); + return; + } + + if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor), ID($bweqx))) { + auto &sig_y = cell->getPort(ID::Y); + auto sig_a = cell->getPort(ID::A); + auto sig_b = cell->getPort(ID::B); + if (cell->type.in(ID($and), ID($or))) { + sig_a.extend_u0(GetSize(sig_y), cell->getParam(ID::A_SIGNED).as_bool()); + sig_b.extend_u0(GetSize(sig_y), cell->getParam(ID::B_SIGNED).as_bool()); + } + forward_tags(sig_y, sig_a); + forward_tags(sig_y, sig_b); + return; + } + + if (cell->type.in(ID($mux), ID($bwmux))) { + auto &sig_y = cell->getPort(ID::Y); + auto &sig_a = cell->getPort(ID::A); + auto &sig_b = cell->getPort(ID::B); + auto sig_s = cell->getPort(ID::S); + + if (cell->type == ID($mux)) + sig_s = SigSpec(sig_s[0], GetSize(sig_y)); + + forward_tags(sig_y, sig_a); + forward_tags(sig_y, sig_b); + forward_tags(sig_y, sig_s); + return; + } + + if (RTLIL::builtin_ff_cell_types().count(cell->type) || cell->type == ID($anyinit)) { + FfData ff(&initvals, cell); + + if (ff.has_clk || ff.has_gclk) + forward_tags(ff.sig_q, ff.sig_d); + return; + } + + // Single output but, sensitive to all inputs + if (cell->type.in( + ID($le), ID($lt), ID($ge), ID($gt), + ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), + ID($reduce_bool), ID($logic_not), ID($logic_or), ID($logic_and), + ID($eq), ID($ne) + )) { + auto &sig_y = cell->getPort(ID::Y); + + add_tags(sig_y[0], tags(cell)); + return; + } + + + // Fallback, propagate tags from all inputs to all outputs + add_tags(cell, tags(cell)); + + if (cell->type.in( + ID($_AND_), ID($_OR_), ID($_NAND_), ID($_NOR_), ID($_ANDNOT_), ID($_ORNOT_), + ID($_XOR_), ID($_XNOR_), ID($_NOT_), ID($_BUF_), ID($_MUX_), + + ID($assert), ID($assume) + )) { + return; + } + + // This isn't a correctness concern (unless cell is a module generating + // tags), but we may end up generating a lot of extra logic when + // reaching this + if (!warned_cells.insert(cell).second) + return; + if (cell->type.isPublic()) + log_warning("Unhandled cell %s (%s) during tag propagation\n", log_id(cell), log_id(cell->type)); + else + log_debug("Unhandled cell %s (%s) during tag propagation\n", log_id(cell), log_id(cell->type)); + } + + void process_cell(IdString tag, Cell *cell) + { + if (cell->type == ID($set_tag)) { + IdString cell_tag = stringf("\\%s", cell->getParam(ID::TAG).decode_string().c_str()); + + auto tag_sig_a = tag_signal(tag, cell->getPort(ID::A)); + auto &sig_y = cell->getPort(ID::Y); + + if (cell_tag == tag) { + auto &sig_set = cell->getPort(ID::SET); + auto &sig_clr = cell->getPort(ID::CLR); + tag_sig_a = autoAnd(NEW_ID, tag_sig_a, autoNot(NEW_ID, sig_clr)); + tag_sig_a = autoOr(NEW_ID, tag_sig_a, sig_set); + } + + emit_tag_signal(tag, sig_y, tag_sig_a); + return; + } + + if (cell->type == ID($get_tag)) { + log_assert(false); + } + + if (cell->type.in(ID($not), ID($pos), ID($_NOT_), ID($_BUF_))) { + auto &sig_y = cell->getPort(ID::Y); + auto sig_a = cell->getPort(ID::A); + if (cell->type.in(ID($not), ID($or))) { + sig_a.extend_u0(GetSize(sig_y), cell->getParam(ID::A_SIGNED).as_bool()); + } + emit_tag_signal(tag, sig_y, tag_signal(tag, sig_a)); + return; + } + + if (cell->type.in( + ID($and), ID($or), + ID($_AND_), ID($_OR_), ID($_NAND_), ID($_NOR_), ID($_ANDNOT_), ID($_ORNOT_) + )) { + auto &sig_y = cell->getPort(ID::Y); + auto sig_a = cell->getPort(ID::A); + auto sig_b = cell->getPort(ID::B); + if (cell->type.in(ID($and), ID($or))) { + sig_a.extend_u0(GetSize(sig_y), cell->getParam(ID::A_SIGNED).as_bool()); + sig_b.extend_u0(GetSize(sig_y), cell->getParam(ID::B_SIGNED).as_bool()); + } + + bool inv_a = false; + bool inv_b = false; + + if (cell->type.in(ID($or), ID($_OR_), ID($_NOR_), ID($_ORNOT_))) + inv_a ^= true, inv_b ^= true; + if (cell->type.in(ID($_ANDNOT_), ID($_ORNOT_))) + inv_b ^= true; + + if (inv_a) + sig_a = autoNot(NEW_ID, sig_a); + if (inv_b) + sig_b = autoNot(NEW_ID, sig_b); + + auto group_sig_a = tag_group_signal(tag, sig_a); + auto group_sig_b = tag_group_signal(tag, sig_b); + + auto tag_sig_a = tag_signal(tag, sig_a); + auto tag_sig_b = tag_signal(tag, sig_b); + + + // Does this input allow propagating (doesn't fix output or same tag group) + sig_a = autoOr(NEW_ID, sig_a, group_sig_a); + sig_b = autoOr(NEW_ID, sig_b, group_sig_b); + + // Mask input tags by whether the other side allows propagation + tag_sig_a = autoAnd(NEW_ID, tag_sig_a, sig_b); + tag_sig_b = autoAnd(NEW_ID, tag_sig_b, sig_a); + + + auto tag_sig = autoOr(NEW_ID, tag_sig_a, tag_sig_b); + emit_tag_signal(tag, sig_y, tag_sig); + return; + } + + if (cell->type.in(ID($xor), ID($xnor), ID($bweqx), ID($_XOR_), ID($_XNOR_))) { + auto &sig_y = cell->getPort(ID::Y); + auto sig_a = cell->getPort(ID::A); + auto sig_b = cell->getPort(ID::B); + if (cell->type.in(ID($xor), ID($xnor))) { + sig_a.extend_u0(GetSize(sig_y), cell->getParam(ID::A_SIGNED).as_bool()); + sig_b.extend_u0(GetSize(sig_y), cell->getParam(ID::B_SIGNED).as_bool()); + } + + auto tag_sig_a = tag_signal(tag, sig_a); + auto tag_sig_b = tag_signal(tag, sig_b); + + auto tag_sig = autoOr(NEW_ID, tag_sig_a, tag_sig_b); + emit_tag_signal(tag, sig_y, tag_sig); + return; + } + + + if (cell->type.in(ID($_MUX_), ID($mux), ID($bwmux))) { + auto &sig_y = cell->getPort(ID::Y); + auto &sig_a = cell->getPort(ID::A); + auto &sig_b = cell->getPort(ID::B); + auto sig_s = cell->getPort(ID::S); + + if (cell->type == ID($mux)) + sig_s = SigSpec(sig_s[0], GetSize(sig_y)); + + auto group_sig_a = tag_group_signal(tag, sig_a); + auto group_sig_b = tag_group_signal(tag, sig_b); + auto group_sig_s = tag_group_signal(tag, sig_s); + + auto prop_s = autoOr(NEW_ID, + autoXor(NEW_ID, sig_a, sig_b), + autoOr(NEW_ID, group_sig_a, group_sig_b)); + + auto prop_a = autoOr(NEW_ID, autoNot(NEW_ID, sig_s), group_sig_s); + auto prop_b = autoOr(NEW_ID, sig_s, group_sig_s); + + auto tag_sig_a = tag_signal(tag, sig_a); + auto tag_sig_b = tag_signal(tag, sig_b); + auto tag_sig_s = tag_signal(tag, sig_s); + + tag_sig_a = autoAnd(NEW_ID, tag_sig_a, prop_a); + tag_sig_b = autoAnd(NEW_ID, tag_sig_b, prop_b); + tag_sig_s = autoAnd(NEW_ID, tag_sig_s, prop_s); + + auto tag_sig = autoOr(NEW_ID, tag_sig_s, + autoOr(NEW_ID, tag_sig_a, tag_sig_b)); + emit_tag_signal(tag, sig_y, tag_sig); + return; + } + + if (cell->type.in(ID($eq), ID($ne), ID($eqx), ID($nex))) { + auto &sig_y = cell->getPort(ID::Y); + auto sig_a = cell->getPort(ID::A); + auto sig_b = cell->getPort(ID::B); + int width = std::max(GetSize(sig_a), GetSize(sig_b)); + sig_a.extend_u0(width, cell->getParam(ID::A_SIGNED).as_bool()); + sig_b.extend_u0(width, cell->getParam(ID::B_SIGNED).as_bool()); + + auto group_sig_a = tag_group_signal(tag, sig_a); + auto group_sig_b = tag_group_signal(tag, sig_b); + + auto tag_sig_a = tag_signal(tag, sig_a); + auto tag_sig_b = tag_signal(tag, sig_b); + + auto group_sig = autoOr(NEW_ID, group_sig_a, group_sig_b); + // The output can only be affected by the tagged inputs if all group-untagged bits are equal + + auto masked_a = autoOr(NEW_ID, sig_a, group_sig); + auto masked_b = autoOr(NEW_ID, sig_b, group_sig); + + auto prop = autoEq(NEW_ID, masked_a, masked_b); + + auto tag_sig = autoAnd(NEW_ID, prop, autoReduceOr(NEW_ID, {tag_sig_a, tag_sig_b})); + tag_sig.extend_u0(GetSize(sig_y), false); + emit_tag_signal(tag, sig_y, tag_sig); + return; + } + + + if (cell->type.in(ID($lt), ID($gt), ID($le), ID($ge))) { + auto &sig_y = cell->getPort(ID::Y); + auto sig_a = cell->getPort(ID::A); + auto sig_b = cell->getPort(ID::B); + int width = std::max(GetSize(sig_a), GetSize(sig_b)); + sig_a.extend_u0(width, cell->getParam(ID::A_SIGNED).as_bool()); + sig_b.extend_u0(width, cell->getParam(ID::B_SIGNED).as_bool()); + + if (cell->type.in(ID($gt), ID($le))) + std::swap(sig_a, sig_b); + + auto group_sig_a = tag_group_signal(tag, sig_a); + auto group_sig_b = tag_group_signal(tag, sig_b); + + auto tag_sig_a = tag_signal(tag, sig_a); + auto tag_sig_b = tag_signal(tag, sig_b); + + auto group_sig = autoOr(NEW_ID, group_sig_a, group_sig_b); + // The output can only be affected by the tagged inputs if the greatest possible sig_a is + // greater or equal to the least possible sig_b + auto masked_a = autoOr(NEW_ID, sig_a, group_sig); + auto masked_b = autoAnd(NEW_ID, sig_b, autoNot(NEW_ID, group_sig)); + + auto prop = autoGe(NEW_ID, masked_a, masked_b); + + auto tag_sig = autoAnd(NEW_ID, prop, autoReduceOr(NEW_ID, {tag_sig_a, tag_sig_b})); + tag_sig.extend_u0(GetSize(sig_y), false); + emit_tag_signal(tag, sig_y, tag_sig); + return; + } + + if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_bool), ID($logic_not))) { + auto &sig_y = cell->getPort(ID::Y); + auto sig_a = cell->getPort(ID::A); + + if (cell->type.in(ID($reduce_or), ID($reduce_bool), ID($logic_not))) + sig_a = autoNot(NEW_ID, sig_a); + + auto group_sig_a = tag_group_signal(tag, sig_a); + auto tag_sig_a = tag_signal(tag, sig_a); + + auto filled = autoOr(NEW_ID, sig_a, group_sig_a); + + auto prop = autoReduceAnd(NEW_ID, filled); + auto tagged = autoReduceOr(NEW_ID, tag_sig_a); + auto tag_sig = autoAnd(NEW_ID, prop, tagged); + tag_sig.extend_u0(GetSize(sig_y), false); + emit_tag_signal(tag, sig_y, tag_sig); + return; + } + + if (RTLIL::builtin_ff_cell_types().count(cell->type) || cell->type == ID($anyinit)) { + FfData ff(&initvals, cell); + // TODO handle some more variants + if ((ff.has_clk || ff.has_gclk) && !ff.has_ce && !ff.has_aload && !ff.has_srst && !ff.has_arst && !ff.has_sr) { + if (ff.has_clk && !tags(ff.sig_clk).empty()) + log_warning("Tags on CLK input ignored for %s (%s)\n", log_id(cell), log_id(cell->type)); + + int width = ff.width; + + auto sig_q = ff.sig_q; + auto sig_d = ff.sig_d; + + ff.name = NEW_ID; + ff.cell = nullptr; + ff.sig_d = tag_signal(tag, ff.sig_d); + ff.sig_q = module->addWire(NEW_ID, width); + ff.is_anyinit = false; + ff.val_init = Const(0, width); + ff.emit(); + + emit_tag_signal(tag, sig_q, ff.sig_q); + return; + } else { + log_warning("Unhandled FF-cell %s (%s), consider running clk2fflogic, async2sync and/or dffunmap\n", log_id(cell), log_id(cell->type)); + + // For unhandled FFs, the default propagation would cause combinational loops + emit_tag_signal(tag, ff.sig_q, Const(0, ff.width)); + return; + } + } + + // Fallback + SigSpec tag_input; + + for (auto &conn : cell->connections()) { + if (cell->input(conn.first)) { + auto tag_sig = tag_signal(tag, conn.second); + tag_input.append(tag_sig); + } + } + + SigBit any_tagged = autoReduceOr(NEW_ID, tag_input); + + for (auto &conn : cell->connections()) { + if (cell->output(conn.first)) { + emit_tag_signal(tag, conn.second, SigSpec(any_tagged, GetSize(conn.second))); + } + } + + // As fallback we propagate all tags from all inputs to all outputs, + // which is an over-approximation (unless the cell is a module that + // generates tags itself in which case it could be arbitrary). + if (warned_cells.insert(cell).second) + log_warning("Unhandled cell %s (%s) while emitting tag signals\n", log_id(cell), log_id(cell->type)); + } + + void emit_tags() + { + warned_cells.clear(); + std::vector get_tag_cells; + for (auto cell : module->selected_cells()) + if (cell->type == ID($get_tag)) + get_tag_cells.push_back(cell); + + for (auto cell : get_tag_cells) { + auto &sig_a = cell->getPort(ID::A); + IdString tag = stringf("\\%s", cell->getParam(ID::TAG).decode_string().c_str()); + + tag_signal(tag, sig_a); + } + + if (options.tag_public) + { + std::vector public_wires; + + for (auto wire : module->selected_wires()) + if (wire->name.isPublic()) + public_wires.push_back(wire); + + for (auto wire : public_wires) { + for (auto tag : tag_pool(tags(SigSpec(wire)))) { + auto tag_sig = tag_signal(tag, SigSpec(wire)); + if (tag_sig.is_fully_zero()) + continue; + + int index = 0; + auto name = module->uniquify(stringf("%s:%s", wire->name.c_str(), tag.c_str() + 1), index); + auto hdlname = wire->get_hdlname_attribute(); + + if (!hdlname.empty()) + hdlname.back() += index ? + stringf(":%s_%d", tag.c_str() + 1, index) : + stringf(":%s", tag.c_str() + 1); + + auto tag_wire = module->addWire(name, wire->width); + + tag_wire->set_bool_attribute(ID::keep); + tag_wire->set_bool_attribute(ID(dft_tag)); + if (!hdlname.empty()) + tag_wire->set_hdlname_attribute(hdlname); + + module->connect(tag_wire, tag_sig); + } + } + } + } + + void replace_dft_cells() + { + std::vector get_tag_cells; + std::vector set_tag_cells; + for (auto cell : module->cells()) { + if (cell->type == ID($get_tag)) + get_tag_cells.push_back(cell); + + if (cell->type == ID($set_tag)) + set_tag_cells.push_back(cell); + + if (cell->type.in(ID($overwrite_tag), ID($original_tag))) + log_error("$overwrite_tag and $original_tag are not supported yet\n"); + // TODO these have to be rewritten as early as possible, so it should be a separate pass invocation + } + + for (auto cell : set_tag_cells) { + auto &sig_a = cell->getPort(ID::A); + auto &sig_y = cell->getPort(ID::Y); + module->connect(sig_y, sig_a); + module->remove(cell); + } + + for (auto cell : get_tag_cells) { + auto &sig_a = cell->getPort(ID::A); + auto &sig_y = cell->getPort(ID::Y); + IdString tag = stringf("\\%s", cell->getParam(ID::TAG).decode_string().c_str()); + + auto tag_sig = tag_signal(tag, sig_a); + module->connect(sig_y, tag_sig); + module->remove(cell); + } + } + + + SigSpec autoAnd(IdString name, const SigSpec &sig_a, const SigSpec &sig_b) + { + log_assert(GetSize(sig_a) == GetSize(sig_b)); + if (sig_a.is_fully_zero() || sig_b.is_fully_ones() || sig_a == sig_b) + return sig_a; + if (sig_a.is_fully_ones() || sig_b.is_fully_zero()) + return sig_b; + + return module->And(name, sig_a, sig_b); + } + + SigSpec autoOr(IdString name, const SigSpec &sig_a, const SigSpec &sig_b) + { + log_assert(GetSize(sig_a) == GetSize(sig_b)); + if (sig_a.is_fully_ones() || sig_b.is_fully_zero() || sig_a == sig_b) + return sig_a; + if (sig_a.is_fully_zero() || sig_b.is_fully_ones()) + return sig_b; + + return module->Or(name, sig_a, sig_b); + } + + SigSpec autoXor(IdString name, const SigSpec &sig_a, const SigSpec &sig_b) + { + log_assert(GetSize(sig_a) == GetSize(sig_b)); + if (sig_a == sig_b) + return Const(State::S0, GetSize(sig_a)); + if (sig_a.is_fully_zero()) + return sig_b; + if (sig_b.is_fully_zero()) + return sig_a; + if (sig_a.is_fully_ones()) + return autoNot(name, sig_b); + if (sig_b.is_fully_ones()) + return autoNot(name, sig_a); + return module->Xor(name, sig_a, sig_b); + } + + SigSpec autoXnor(IdString name, const SigSpec &sig_a, const SigSpec &sig_b) + { + log_assert(GetSize(sig_a) == GetSize(sig_b)); + if (sig_a == sig_b) + return Const(State::S1, GetSize(sig_a)); + if (sig_a.is_fully_ones()) + return sig_b; + if (sig_b.is_fully_ones()) + return sig_a; + if (sig_a.is_fully_zero()) + return autoNot(name, sig_b); + if (sig_b.is_fully_zero()) + return autoNot(name, sig_a); + return module->Xnor(name, sig_a, sig_b); + } + + SigSpec autoNot(IdString name, const SigSpec &sig_a) + { + if (sig_a.is_fully_const()) { + auto const_val = sig_a.as_const(); + for (auto &bit : const_val.bits) + bit = bit == State::S0 ? State::S1 : bit == State::S1 ? State::S0 : bit; + return const_val; + } + return module->Not(name, sig_a); + } + + SigSpec autoEq(IdString name, const SigSpec &sig_a, const SigSpec &sig_b) + { + log_assert(GetSize(sig_a) == GetSize(sig_b)); + if (sig_a == sig_b) + return State::S1; + for (int i = 0; i < GetSize(sig_a); i++) { + auto bit_a = sig_a[i]; + auto bit_b = sig_b[i]; + if (bit_a.is_wire() || bit_b.is_wire()) + continue; + if ((bit_a.data == State::S0 && bit_b.data == State::S1) || + (bit_a.data == State::S1 && bit_b.data == State::S0)) + return State::S0; + } + + return module->Eq(name, sig_a, sig_b); + } + + SigSpec autoGe(IdString name, const SigSpec &sig_a, const SigSpec &sig_b) + { + log_assert(GetSize(sig_a) == GetSize(sig_b)); + if (sig_a == sig_b || sig_a.is_fully_ones()) + return State::S1; + if (sig_b.is_fully_zero()) + return State::S1; + + return module->Ge(name, sig_a, sig_b); + } + + SigSpec autoReduceAnd(IdString name, const SigSpec &sig_a) + { + if (GetSize(sig_a) == 0) + return State::S1; + + if (GetSize(sig_a) == 1 || sig_a == SigSpec(sig_a[0], GetSize(sig_a))) + return sig_a[0]; + for (auto bit : sig_a) + if (!bit.is_wire() && bit.data == State::S0) + return State::S0; + if (sig_a.is_fully_ones()) + return State::S1; + return module->ReduceAnd(name, sig_a); + } + + SigSpec autoReduceOr(IdString name, const SigSpec &sig_a) + { + if (GetSize(sig_a) == 0) + return State::S0; + + if (GetSize(sig_a) == 1 || sig_a == SigSpec(sig_a[0], GetSize(sig_a))) + return sig_a[0]; + for (auto bit : sig_a) + if (!bit.is_wire() && bit.data == State::S1) + return State::S1; + if (sig_a.is_fully_zero()) + return State::S0; + return module->ReduceOr(name, sig_a); + } +}; + +struct DftTagPass : public Pass { + DftTagPass() : Pass("dft_tag", "create tagging logic for data flow tracking") {} + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" dft_tag [options] [selection]\n"); + log("\n"); + log("This pass... TODO\n"); + log("\n"); + log(" -tag-public\n"); + log(" For each public wire that may carry tagged data, create a new public\n"); + log(" wire (named :) that carries the tag bits. Note\n"); + log(" that without this, tagging logic will only be emitted as required\n"); + log(" for uses of $get_tag.\n"); + log("\n"); + } + + void execute(std::vector args, RTLIL::Design *design) override + { + DftTagOptions options; + + log_header(design, "Executing DFT_TAG pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-tag-public") { + options.tag_public = true; + continue; + } + break; + } + + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) { + DftTagWorker worker(module, options); + + log_debug("Propagate tagged signals.\n"); + worker.propagate_tags(); + + log_debug("Emit tag signals and logic.\n"); + worker.emit_tags(); + + log_debug("Replace dft cells.\n"); + worker.replace_dft_cells(); + } + } +} DftTagPass; + +PRIVATE_NAMESPACE_END From 46a35da28cfe832b5da6b87ec6642574efb47d92 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 29 Aug 2023 15:47:05 +0200 Subject: [PATCH 040/173] Add `future` pass to resolve `$future_ff` cells --- passes/cmds/Makefile.inc | 1 + passes/cmds/future.cc | 140 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 passes/cmds/future.cc diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc index f3cd9b9509b..d7e572462b0 100644 --- a/passes/cmds/Makefile.inc +++ b/passes/cmds/Makefile.inc @@ -47,3 +47,4 @@ OBJS += passes/cmds/sta.o OBJS += passes/cmds/clean_zerowidth.o OBJS += passes/cmds/xprop.o OBJS += passes/cmds/dft_tag.o +OBJS += passes/cmds/future.o diff --git a/passes/cmds/future.cc b/passes/cmds/future.cc new file mode 100644 index 00000000000..b03613c9bd2 --- /dev/null +++ b/passes/cmds/future.cc @@ -0,0 +1,140 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2023 Jannis Harder + * + * 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/celltypes.h" +#include "kernel/ff.h" +#include "kernel/ffinit.h" +#include "kernel/modtools.h" +#include "kernel/sigtools.h" +#include "kernel/utils.h" +#include "kernel/yosys.h" +#include + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct FutureOptions { +}; + +struct FutureWorker { + Module *module; + FutureOptions options; + ModWalker modwalker; + SigMap &sigmap; + FfInitVals initvals; + + dict future_ff_signals; + + FutureWorker(Module *module, FutureOptions options) : + module(module), options(options), modwalker(module->design), sigmap(modwalker.sigmap) + { + modwalker.setup(module); + initvals.set(&modwalker.sigmap, module); + + std::vector replaced_cells; + for (auto cell : module->selected_cells()) { + if (cell->type != ID($future_ff)) + continue; + + module->connect(cell->getPort(ID::Y), future_ff(cell->getPort(ID::A))); + replaced_cells.push_back(cell); + } + + for (auto cell : replaced_cells) { + module->remove(cell); + } + } + + SigSpec future_ff(SigSpec sig) + { + for (auto &bit : sig) { + bit = future_ff(bit); + } + return sig; + } + + SigBit future_ff(SigBit bit) + { + if (!bit.is_wire()) + return bit; + + auto found = future_ff_signals.find(bit); + if (found != future_ff_signals.end()) + return found->second; + + auto found_driver = modwalker.signal_drivers.find(bit); + if (found_driver == modwalker.signal_drivers.end() || found_driver->second.size() < 1) + log_error("No driver for future_ff target signal %s found\n", log_signal(bit)); + if (found_driver->second.size() > 1) + log_error("Found multiple drivers for future_ff target signal %s\n", log_signal(bit)); + auto driver = *found_driver->second.begin(); + if (!RTLIL::builtin_ff_cell_types().count(driver.cell->type) && driver.cell->type != ID($anyinit)) + log_error("Driver for future_ff target signal %s has non-FF cell type %s\n", log_signal(bit), log_id(driver.cell->type)); + + FfData ff(&initvals, driver.cell); + + if (!ff.has_clk && !ff.has_gclk) + log_error("Driver for future_ff target signal %s has cell type %s, which is not clocked\n", log_signal(bit), + log_id(driver.cell->type)); + + ff.unmap_ce_srst(); + + // We insert all bits into the mapping, because unmap_ce_srst might + // have removed the cell which is still present in the modwalker data. + // By inserting all bits driven by th FF we ensure that we'll never use + // that stale modwalker data again. + + for (int i = 0; i < ff.width; ++i) { + future_ff_signals.emplace(ff.sig_q[i], ff.sig_d[i]); + } + + return future_ff_signals.at(bit); + } +}; + +struct FuturePass : public Pass { + FuturePass() : Pass("future", "resolve future sampled value functions") {} + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" future [options] [selection]\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) override + { + FutureOptions options; + + log_header(design, "Executing FUTURE pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + + break; + } + + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) { + FutureWorker worker(module, options); + } + } +} FuturePass; + +PRIVATE_NAMESPACE_END From 78ff40d1b28ed62f3d98c1ed970ce7ba482cf8d6 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 29 Aug 2023 15:50:17 +0200 Subject: [PATCH 041/173] Run `future` as part of `prep` --- techlibs/common/prep.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/techlibs/common/prep.cc b/techlibs/common/prep.cc index c354956bcf4..e9176304d48 100644 --- a/techlibs/common/prep.cc +++ b/techlibs/common/prep.cc @@ -189,6 +189,7 @@ struct PrepPass : public ScriptPass run(ifxmode ? "proc -ifx" : "proc"); if (help_mode || flatten) run("flatten", "(if -flatten)"); + run("future"); run(nokeepdc ? "opt_expr" : "opt_expr -keepdc"); run("opt_clean"); run("check"); From 62b4df49891034d48b3f24e78b83e7c49b23432c Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 29 Aug 2023 17:40:51 +0200 Subject: [PATCH 042/173] dft_tag: Implement `$overwrite_tag` and `$original_tag` This does not correctly handle an `$overwrite_tag` on a module output, but since we currently require the user to flatten the design for cross-module dft, this cannot be observed from within the design, only by manually inspecting the signals in the design. --- kernel/rtlil.cc | 43 ++++++++++++------- kernel/rtlil.h | 9 ++-- passes/cmds/dft_tag.cc | 91 +++++++++++++++++++++++++++++++++++++++-- passes/opt/opt_clean.cc | 3 ++ 4 files changed, 123 insertions(+), 23 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 7d257714460..51d02091308 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -3280,13 +3280,13 @@ RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name, const std::string return sig; } -RTLIL::SigSpec RTLIL::Module::SetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src) +RTLIL::SigSpec RTLIL::Module::SetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src) { - RTLIL::SigSpec sig = addWire(NEW_ID, sig_e.size()); + RTLIL::SigSpec sig = addWire(NEW_ID, sig_a.size()); Cell *cell = addCell(name, ID($set_tag)); - cell->parameters[ID::WIDTH] = sig_e.size(); + cell->parameters[ID::WIDTH] = sig_a.size(); cell->parameters[ID::TAG] = tag; - cell->setPort(ID::A, sig_e); + cell->setPort(ID::A, sig_a); cell->setPort(ID::SET, sig_s); cell->setPort(ID::CLR, sig_c); cell->setPort(ID::Y, sig); @@ -3294,37 +3294,50 @@ RTLIL::SigSpec RTLIL::Module::SetTag(RTLIL::IdString name, const std::string &ta return sig; } -RTLIL::SigSpec RTLIL::Module::GetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const std::string &src) +RTLIL::Cell* RTLIL::Module::addSetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_y, const std::string &src) { - RTLIL::SigSpec sig = addWire(NEW_ID, sig_e.size()); + Cell *cell = addCell(name, ID($set_tag)); + cell->parameters[ID::WIDTH] = sig_a.size(); + cell->parameters[ID::TAG] = tag; + cell->setPort(ID::A, sig_a); + cell->setPort(ID::SET, sig_s); + cell->setPort(ID::CLR, sig_c); + cell->setPort(ID::Y, sig_y); + cell->set_src_attribute(src); + return cell; +} + +RTLIL::SigSpec RTLIL::Module::GetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src) +{ + RTLIL::SigSpec sig = addWire(NEW_ID, sig_a.size()); Cell *cell = addCell(name, ID($get_tag)); - cell->parameters[ID::WIDTH] = sig_e.size(); + cell->parameters[ID::WIDTH] = sig_a.size(); cell->parameters[ID::TAG] = tag; - cell->setPort(ID::A, sig_e); + cell->setPort(ID::A, sig_a); cell->setPort(ID::Y, sig); cell->set_src_attribute(src); return sig; } -RTLIL::Cell* RTLIL::Module::addOverwriteTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src) +RTLIL::Cell* RTLIL::Module::addOverwriteTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src) { RTLIL::Cell *cell = addCell(name, ID($overwrite_tag)); - cell->parameters[ID::WIDTH] = sig_e.size(); + cell->parameters[ID::WIDTH] = sig_a.size(); cell->parameters[ID::TAG] = tag; - cell->setPort(ID::A, sig_e); + cell->setPort(ID::A, sig_a); cell->setPort(ID::SET, sig_s); cell->setPort(ID::CLR, sig_c); cell->set_src_attribute(src); return cell; } -RTLIL::SigSpec RTLIL::Module::OriginalTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const std::string &src) +RTLIL::SigSpec RTLIL::Module::OriginalTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src) { - RTLIL::SigSpec sig = addWire(NEW_ID, sig_e.size()); + RTLIL::SigSpec sig = addWire(NEW_ID, sig_a.size()); Cell *cell = addCell(name, ID($original_tag)); - cell->parameters[ID::WIDTH] = sig_e.size(); + cell->parameters[ID::WIDTH] = sig_a.size(); cell->parameters[ID::TAG] = tag; - cell->setPort(ID::A, sig_e); + cell->setPort(ID::A, sig_a); cell->setPort(ID::Y, sig); cell->set_src_attribute(src); return sig; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 012865a75c6..c50d75e9087 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1465,10 +1465,11 @@ struct RTLIL::Module : public RTLIL::AttrObject RTLIL::SigSpec Allseq (RTLIL::IdString name, int width = 1, const std::string &src = ""); RTLIL::SigSpec Initstate (RTLIL::IdString name, const std::string &src = ""); - RTLIL::SigSpec SetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = ""); - RTLIL::SigSpec GetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const std::string &src = ""); - RTLIL::Cell* addOverwriteTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = ""); - RTLIL::SigSpec OriginalTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const std::string &src = ""); + RTLIL::SigSpec SetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = ""); + RTLIL::Cell* addSetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_y, const std::string &src = ""); + RTLIL::SigSpec GetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src = ""); + RTLIL::Cell* addOverwriteTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = ""); + RTLIL::SigSpec OriginalTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src = ""); RTLIL::SigSpec FutureFF (RTLIL::IdString name, const RTLIL::SigSpec &sig_e, const std::string &src = ""); #ifdef WITH_PYTHON diff --git a/passes/cmds/dft_tag.cc b/passes/cmds/dft_tag.cc index 24fdf9714c8..9fd356ef65d 100644 --- a/passes/cmds/dft_tag.cc +++ b/passes/cmds/dft_tag.cc @@ -28,7 +28,8 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct DftTagOptions { - bool tag_public; + bool tag_public = false; + bool overwrite_only = false; }; struct DftTagWorker { @@ -80,6 +81,78 @@ struct DftTagWorker { tag_sets(tmp_tag_set); } + void resolve_overwrites() + { + std::vector overwrite_cells; + std::vector original_cells; + + bool design_changed = false; + + for (auto cell : module->cells()) { + if (cell->type == ID($overwrite_tag)) + overwrite_cells.push_back(cell); + + if (cell->type == ID($original_tag)) + original_cells.push_back(cell); + } + + for (auto cell : overwrite_cells) { + log_debug("Applying $overwrite_tag %s for signal %s\n", log_id(cell->name), log_signal(cell->getPort(ID::A))); + SigSpec orig_signal = cell->getPort(ID::A); + SigSpec interposed_signal = divert_users(orig_signal); + auto *set_tag_cell = module->addSetTag(NEW_ID, cell->getParam(ID::TAG).decode_string(), orig_signal, cell->getPort(ID::SET), cell->getPort(ID::CLR), interposed_signal); + modwalker.add_cell(set_tag_cell); // Make sure the next $overwrite_tag sees the new connections + design_changed = true; + } + + for (auto cell : overwrite_cells) { + module->remove(cell); + } + for (auto cell : original_cells) { + cell->type = ID($get_tag); + } + + if (design_changed) + modwalker.setup(module); + } + + SigSpec divert_users(SigSpec signal) + { + SigSpec signal_mapped = sigmap(signal); + signal_mapped.sort_and_unify(); + if (GetSize(signal_mapped) < GetSize(signal)) + log_warning("Detected $overwrite_tag on signal %s which contains repeated bits, this can result in unexpected behavior.\n", log_signal(signal)); + SigSpec new_wire = module->addWire(NEW_ID, GetSize(signal)); + for (int i = 0; i < GetSize(new_wire); ++i) + divert_users(signal[i], new_wire[i]); + return new_wire; + } + + void divert_users(SigBit driver_bit, SigBit interposed_bit) + { + dict, SigSpec> updated_ports; + // TODO also check module outputs + auto found = modwalker.signal_consumers.find(driver_bit); + if (found == modwalker.signal_consumers.end()) + return; + for (auto &consumer : found->second) { + if (consumer.cell->type.in(ID($original_tag))) + continue; + if (sigmap(consumer.cell->getPort(consumer.port)[consumer.offset]) != driver_bit) + continue; + std::pair key = {consumer.cell, consumer.port}; + auto found_port = updated_ports.find(key); + if (found_port == updated_ports.end()) { + updated_ports.emplace(key, consumer.cell->getPort(consumer.port)); + } + updated_ports[key][consumer.offset] = interposed_bit; + } + for (auto &update : updated_ports) { + update.first.first->setPort(update.first.second, update.second); + modwalker.add_cell(update.first.first); // Make sure the next $overwrite_tag sees the new connections + } + } + const pool &tag_pool(tag_set set) { return tag_sets[set.index]; } tag_set singleton(IdString tag) @@ -730,9 +803,7 @@ struct DftTagWorker { if (cell->type == ID($set_tag)) set_tag_cells.push_back(cell); - if (cell->type.in(ID($overwrite_tag), ID($original_tag))) - log_error("$overwrite_tag and $original_tag are not supported yet\n"); - // TODO these have to be rewritten as early as possible, so it should be a separate pass invocation + log_assert(!cell->type.in(ID($overwrite_tag), ID($original_tag))); } for (auto cell : set_tag_cells) { @@ -889,6 +960,8 @@ struct DftTagPass : public Pass { log("\n"); log("This pass... TODO\n"); log("\n"); + log(" -overwrite-only\n"); + log(" Only process $overwrite_tag and $original_tag cells.\n"); log(" -tag-public\n"); log(" For each public wire that may carry tagged data, create a new public\n"); log(" wire (named :) that carries the tag bits. Note\n"); @@ -909,6 +982,10 @@ struct DftTagPass : public Pass { options.tag_public = true; continue; } + if (args[argidx] == "-overwrite-only") { + options.overwrite_only = true; + continue; + } break; } @@ -917,6 +994,12 @@ struct DftTagPass : public Pass { for (auto module : design->selected_modules()) { DftTagWorker worker(module, options); + log_debug("Resolve overwrite_tag and original_tag.\n"); + worker.resolve_overwrites(); + + if (options.overwrite_only) + continue; + log_debug("Propagate tagged signals.\n"); worker.propagate_tags(); diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 4da67cf630f..a219e470813 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -76,6 +76,9 @@ struct keep_cache_t if (cell->type.in(ID($assert), ID($assume), ID($live), ID($fair), ID($cover))) return true; + if (cell->type.in(ID($overwrite_tag))) + return true; + if (!ignore_specify && cell->type.in(ID($specify2), ID($specify3), ID($specrule))) return true; From 0e8a4adb59f34e70acbe1cb1b8af5b015f4eb2b3 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 5 Sep 2023 11:52:21 +0200 Subject: [PATCH 043/173] verific: Update YOSYSHQ_VERIFIC_API_VERSION --- frontends/verific/verific.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index d30b46082e1..a67244d7ab3 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -74,7 +74,7 @@ USING_YOSYS_NAMESPACE # error "Only YosysHQ flavored Verific is supported. Please contact office@yosyshq.com for commercial support for Yosys+Verific." #endif -#if YOSYSHQ_VERIFIC_API_VERSION < 20210801 +#if YOSYSHQ_VERIFIC_API_VERSION < 20230901 # error "Please update your version of YosysHQ flavored Verific." #endif From e9a11dd08863ad0bfcb4d21f7d152da710bacdd8 Mon Sep 17 00:00:00 2001 From: Catherine Date: Wed, 13 Sep 2023 11:35:46 +0000 Subject: [PATCH 044/173] Update ABC for WASI support. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0c79636497f..b5a89ae0782 100644 --- a/Makefile +++ b/Makefile @@ -165,7 +165,7 @@ bumpversion: # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = 9537f39 +ABCREV = 6b66b81 ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) From c7d7cfeaca6c79b871aca39c0878cf189390c497 Mon Sep 17 00:00:00 2001 From: Catherine Date: Wed, 13 Sep 2023 15:06:27 +0000 Subject: [PATCH 045/173] Update ABC for WASI support. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b5a89ae0782..178d6ee4d30 100644 --- a/Makefile +++ b/Makefile @@ -165,7 +165,7 @@ bumpversion: # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = 6b66b81 +ABCREV = daad9ed ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) From b84ed5d3ad2ac8b533e1d6a83dbdb6d5c2be9ce7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 14 Sep 2023 00:14:42 +0000 Subject: [PATCH 046/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 178d6ee4d30..d7ecff99921 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+21 +YOSYS_VER := 0.33+34 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 9042124ba7ab746b466a1450f18462d1741afa79 Mon Sep 17 00:00:00 2001 From: Tim Paine <3105306+timkpaine@users.noreply.github.com> Date: Fri, 15 Sep 2023 14:24:45 -0400 Subject: [PATCH 047/173] Alphabetize headers to be installed, include some missing required ones for plugins, fixes https://github.com/chipsalliance/synlig/pull/1972 https://github.com/dau-dev/tools/issues/6 --- Makefile | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index d7ecff99921..a93930be0c9 100644 --- a/Makefile +++ b/Makefile @@ -606,31 +606,35 @@ Q = S = endif -$(eval $(call add_include_file,kernel/yosys.h)) -$(eval $(call add_include_file,kernel/hashlib.h)) -$(eval $(call add_include_file,kernel/log.h)) -$(eval $(call add_include_file,kernel/rtlil.h)) $(eval $(call add_include_file,kernel/binding.h)) -$(eval $(call add_include_file,kernel/register.h)) $(eval $(call add_include_file,kernel/cellaigs.h)) -$(eval $(call add_include_file,kernel/celltypes.h)) $(eval $(call add_include_file,kernel/celledges.h)) +$(eval $(call add_include_file,kernel/celltypes.h)) $(eval $(call add_include_file,kernel/consteval.h)) $(eval $(call add_include_file,kernel/constids.inc)) -$(eval $(call add_include_file,kernel/sigtools.h)) -$(eval $(call add_include_file,kernel/modtools.h)) -$(eval $(call add_include_file,kernel/macc.h)) -$(eval $(call add_include_file,kernel/utils.h)) -$(eval $(call add_include_file,kernel/satgen.h)) -$(eval $(call add_include_file,kernel/qcsat.h)) +$(eval $(call add_include_file,kernel/cost.h)) $(eval $(call add_include_file,kernel/ff.h)) $(eval $(call add_include_file,kernel/ffinit.h)) +$(eval $(call add_include_file,kernel/ffmerge.h)) +$(eval $(call add_include_file,kernel/fmt.h)) ifeq ($(ENABLE_ZLIB),1) $(eval $(call add_include_file,kernel/fstdata.h)) endif +$(eval $(call add_include_file,kernel/hashlib.h)) +$(eval $(call add_include_file,kernel/json.h)) +$(eval $(call add_include_file,kernel/log.h)) +$(eval $(call add_include_file,kernel/macc.h)) +$(eval $(call add_include_file,kernel/modtools.h)) $(eval $(call add_include_file,kernel/mem.h)) +$(eval $(call add_include_file,kernel/qcsat.h)) +$(eval $(call add_include_file,kernel/register.h)) +$(eval $(call add_include_file,kernel/rtlil.h)) +$(eval $(call add_include_file,kernel/satgen.h)) +$(eval $(call add_include_file,kernel/sigtools.h)) +$(eval $(call add_include_file,kernel/timinginfo.h)) +$(eval $(call add_include_file,kernel/utils.h)) +$(eval $(call add_include_file,kernel/yosys.h)) $(eval $(call add_include_file,kernel/yw.h)) -$(eval $(call add_include_file,kernel/json.h)) $(eval $(call add_include_file,libs/ezsat/ezsat.h)) $(eval $(call add_include_file,libs/ezsat/ezminisat.h)) ifeq ($(ENABLE_ZLIB),1) From 82221211642fdd23ecf90e853dffa05411bb62de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 13 Sep 2023 12:47:18 +0200 Subject: [PATCH 048/173] verific: Add test of accurate semantics in memory inference --- tests/verific/memory_semantics.ys | 94 +++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 tests/verific/memory_semantics.ys diff --git a/tests/verific/memory_semantics.ys b/tests/verific/memory_semantics.ys new file mode 100644 index 00000000000..92f4fd2dc44 --- /dev/null +++ b/tests/verific/memory_semantics.ys @@ -0,0 +1,94 @@ +verific -sv < Date: Tue, 19 Sep 2023 00:23:00 +0000 Subject: [PATCH 049/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a93930be0c9..ab7ea18c060 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+34 +YOSYS_VER := 0.33+53 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 7d07615dee4d245dd97e6f4f643dde73f41a2c81 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Mon, 18 Sep 2023 23:26:35 -0400 Subject: [PATCH 050/173] allow attributes in front of ++/-- statements --- frontends/verilog/verilog_parser.y | 24 ++++++++++++------------ tests/verilog/asgn_expr.sv | 8 ++++---- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index d901b3b558d..04bf2c87e50 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -301,14 +301,18 @@ static void ensureAsgnExprAllowed() } // add a pre/post-increment/decrement statement -static const AstNode *addIncOrDecStmt(AstNode *lhs, dict *attr, AST::AstNodeType op, YYLTYPE begin, YYLTYPE end) +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 (attr != nullptr) - append_attr(stmt, attr); + if (stmt_attr != nullptr) + append_attr(stmt, stmt_attr); ast_stack.back()->children.push_back(stmt); return stmt; } @@ -317,7 +321,7 @@ static const AstNode *addIncOrDecStmt(AstNode *lhs, dict *at static AstNode *addIncOrDecExpr(AstNode *lhs, dict *attr, AST::AstNodeType op, YYLTYPE begin, YYLTYPE end, bool undo) { ensureAsgnExprAllowed(); - const AstNode *stmt = addIncOrDecStmt(lhs, attr, op, begin, end); + 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) { @@ -2666,14 +2670,10 @@ simple_behavioral_stmt: append_attr(node, $1); } | attr lvalue attr inc_or_dec_op { - // The position 1 attr to avoid shift/reduce conflicts with the - // other productions. We reject attributes in that position. - if (!$1->empty()) - frontend_verilog_yyerror("Attributes are not allowed on this size of the lvalue in an inc_or_dec_expression!"); - addIncOrDecStmt($2, $3, $4, @1, @4); - } | - inc_or_dec_op attr lvalue { - addIncOrDecStmt($3, $2, $1, @1, @3); + addIncOrDecStmt($1, $2, $3, $4, @1, @4); + } | + attr inc_or_dec_op attr lvalue { + addIncOrDecStmt($1, $4, $3, $2, @1, @4); } | attr lvalue OP_LE delay expr { AstNode *node = new AstNode(AST_ASSIGN_LE, $2, $5); diff --git a/tests/verilog/asgn_expr.sv b/tests/verilog/asgn_expr.sv index 567034d107d..9b874ede33b 100644 --- a/tests/verilog/asgn_expr.sv +++ b/tests/verilog/asgn_expr.sv @@ -13,21 +13,21 @@ module top; // post-increment/decrement statements x++; check(1, 0, 0); - y (* foo *) ++; + (* bar *) y (* foo *) ++; check(1, 1, 0); z--; check(1, 1, -1); - z (* foo *) --; + (* bar *) z (* foo *) --; check(1, 1, -2); // pre-increment/decrement statements are equivalent ++z; check(1, 1, -1); - ++ (* foo *) z; + (* bar *) ++ (* foo *) z; check(1, 1, 0); --x; check(0, 1, 0); - -- (* foo *) y; + (* bar *) -- (* foo *) y; check(0, 0, 0); // procedural pre-increment/decrement expressions From 28e99f2b8c50557e0376fbded1c77236a987ecec Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Mon, 18 Sep 2023 23:35:18 -0400 Subject: [PATCH 051/173] fix width of post-increment/decrement expressions --- frontends/verilog/verilog_parser.y | 2 +- tests/verilog/asgn_expr.sv | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 04bf2c87e50..cb8c453c087 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -325,7 +325,7 @@ static AstNode *addIncOrDecExpr(AstNode *lhs, dict *attr, AS log_assert(stmt->type == AST_ASSIGN_EQ); AstNode *expr = stmt->children[0]->clone(); if (undo) { - AstNode *minus_one = AstNode::mkconst_int(-1, true); + AstNode *minus_one = AstNode::mkconst_int(-1, true, 1); expr = new AstNode(op, expr, minus_one); } SET_AST_NODE_LOC(expr, begin, end); diff --git a/tests/verilog/asgn_expr.sv b/tests/verilog/asgn_expr.sv index 9b874ede33b..25f9caa33d1 100644 --- a/tests/verilog/asgn_expr.sv +++ b/tests/verilog/asgn_expr.sv @@ -56,5 +56,18 @@ module top; check(96, 200, 24); y = (z >>= 1'sb1) * 2; // shift is implicitly cast to unsigned check(96, 24, 12); + + // check width of post-increment expressions + z = (y = 0); + begin + byte w; + w = 0; + x = {1'b1, ++w}; + check(257, 0, 0); + assert (w == 1); + x = {2'b10, w++}; + check(513, 0, 0); + assert (w == 2); + end end endmodule From 18855f23ce866c014e8be3e4dc652b80deca121f Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 19 Sep 2023 12:00:10 +0200 Subject: [PATCH 052/173] Set src attribute for verific with full info --- frontends/verific/verific.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index a67244d7ab3..cd844dceeee 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -265,7 +265,7 @@ void VerificImporter::import_attributes(dict &att Att *attr; if (obj->Linefile()) - attributes[ID::src] = stringf("%s:%d", LineFile::GetFileName(obj->Linefile()), LineFile::GetLineNo(obj->Linefile())); + attributes[ID::src] = stringf("%s:%d.%d-%d.%d", LineFile::GetFileName(obj->Linefile()), obj->Linefile()->GetLeftLine(), obj->Linefile()->GetLeftCol(), obj->Linefile()->GetRightLine(), obj->Linefile()->GetRightCol()); FOREACH_ATTRIBUTE(obj, mi, attr) { if (attr->Key()[0] == ' ' || attr->Value() == nullptr) From 35a05686c4e9987441ac298f5d631f1785e272fd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 00:15:04 +0000 Subject: [PATCH 053/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ab7ea18c060..a75af96b555 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+53 +YOSYS_VER := 0.33+56 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From e0042bdff74a6895bff04d9fbd42ad4c4713369b Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Wed, 20 Sep 2023 15:49:05 -0700 Subject: [PATCH 054/173] Speed up TopoSort. The main sorting algorithm implementation in TopoSort::sort_worker is 11-12x faster. Overall, the complete sequence of building the graph and sorting is about 2.5-3x faster. The overall impact in e.g. the replace_const_cells optimization pass is a ~25% speedup. End-to-end impact on our synthesis flow is about 3%. --- kernel/utils.h | 182 +++++++++++++++++++++++--------------- passes/cmds/glift.cc | 2 +- passes/opt/opt_expr.cc | 15 ++-- passes/opt/share.cc | 2 +- passes/techmap/flatten.cc | 2 +- 5 files changed, 125 insertions(+), 78 deletions(-) diff --git a/kernel/utils.h b/kernel/utils.h index d37f045ff7c..e452f380e63 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -31,35 +31,31 @@ YOSYS_NAMESPACE_BEGIN // A map-like container, but you can save and restore the state // ------------------------------------------------ -template> -struct stackmap -{ -private: - std::vector> backup_state; +template > struct stackmap { + private: + std::vector> backup_state; dict current_state; static T empty_tuple; -public: - stackmap() { } - stackmap(const dict &other) : current_state(other) { } + public: + stackmap() {} + stackmap(const dict &other) : current_state(other) {} - template - void operator=(const Other &other) + template stackmap &operator=(const Other &other) { - for (auto &it : current_state) + for (const auto &it : current_state) if (!backup_state.empty() && backup_state.back().count(it.first) == 0) backup_state.back()[it.first] = new T(it.second); current_state.clear(); - for (auto &it : other) + for (const auto &it : other) set(it.first, it.second); - } - bool has(const Key &k) - { - return current_state.count(k) != 0; + return *this; } + bool has(const Key &k) { return current_state.count(k) != 0; } + void set(const Key &k, const T &v) { if (!backup_state.empty() && backup_state.back().count(k) == 0) @@ -83,7 +79,7 @@ struct stackmap void reset(const Key &k) { - for (int i = GetSize(backup_state)-1; i >= 0; i--) + for (int i = GetSize(backup_state) - 1; i >= 0; i--) if (backup_state[i].count(k) != 0) { if (backup_state[i].at(k) == nullptr) current_state.erase(k); @@ -94,20 +90,14 @@ struct stackmap current_state.erase(k); } - const dict &stdmap() - { - return current_state; - } + const dict &stdmap() { return current_state; } - void save() - { - backup_state.resize(backup_state.size()+1); - } + void save() { backup_state.resize(backup_state.size() + 1); } void restore() { log_assert(!backup_state.empty()); - for (auto &it : backup_state.back()) + for (const auto &it : backup_state.back()) if (it.second != nullptr) { current_state[it.first] = *it.second; delete it.second; @@ -123,46 +113,116 @@ struct stackmap } }; - // ------------------------------------------------ // A simple class for topological sorting // ------------------------------------------------ -template> -struct TopoSort +template , typename OPS = hash_ops> class TopoSort { - bool analyze_loops, found_loops; - std::map, C> database; - std::set> loops; + public: + // We use this ordering of the edges in the adjacency matrix for + // exact compatibility with an older implementation. + struct IndirectCmp { + IndirectCmp(const std::vector &nodes) : nodes_(nodes) {} + bool operator()(int a, int b) const + { + log_assert(static_cast(a) < nodes_.size()); + log_assert(static_cast(b) < nodes_.size()); + return node_cmp_(nodes_[a], nodes_[b]); + } + const C node_cmp_; + const std::vector &nodes_; + }; + + bool analyze_loops; + std::map node_to_index; + std::vector> edges; std::vector sorted; + std::set> loops; - TopoSort() + public: + TopoSort() : indirect_cmp(nodes) { analyze_loops = true; found_loops = false; } - void node(T n) + int node(T n) + { + auto it = node_to_index.find(n); + if (it == node_to_index.end()) { + int index = static_cast(nodes.size()); + node_to_index[n] = index; + nodes.push_back(n); + edges.push_back(std::set(indirect_cmp)); + return index; + } + return it->second; + } + + void edge(int l_index, int r_index) { edges[r_index].insert(l_index); } + + void edge(T left, T right) { edge(node(left), node(right)); } + + bool has_edges(const T &node) + { + auto it = node_to_index.find(node); + return it == node_to_index.end() || !edges[it->second].empty(); + } + + bool sort() { - if (database.count(n) == 0) - database[n] = std::set(); + log_assert(GetSize(node_to_index) == GetSize(edges)); + log_assert(GetSize(nodes) == GetSize(edges)); + + loops.clear(); + sorted.clear(); + found_loops = false; + + std::vector marked_cells(edges.size(), false); + std::vector active_cells(edges.size(), false); + std::vector active_stack; + + marked_cells.reserve(edges.size()); + sorted.reserve(edges.size()); + + for (const auto &it : node_to_index) + sort_worker(it.second, marked_cells, active_cells, active_stack); + + log_assert(GetSize(sorted) == GetSize(nodes)); + + return !found_loops; } - void edge(T left, T right) + // Build the more expensive representation of edges for + // a few passes that use it directly. + std::map, C> get_database() { - node(left); - database[right].insert(left); + std::map, C> database; + for (size_t i = 0; i < nodes.size(); ++i) { + std::set converted_edge_set; + for (int other_node : edges[i]) { + converted_edge_set.insert(nodes[other_node]); + } + database.emplace(nodes[i], converted_edge_set); + } + return database; } - void sort_worker(const T &n, std::set &marked_cells, std::set &active_cells, std::vector &active_stack) + private: + bool found_loops; + std::vector nodes; + const IndirectCmp indirect_cmp; + void sort_worker(const int root_index, std::vector &marked_cells, std::vector &active_cells, std::vector &active_stack) { - if (active_cells.count(n)) { + if (active_cells[root_index]) { found_loops = true; if (analyze_loops) { std::set loop; - for (int i = GetSize(active_stack)-1; i >= 0; i--) { - loop.insert(active_stack[i]); - if (active_stack[i] == n) + for (int i = GetSize(active_stack) - 1; i >= 0; i--) { + const int index = active_stack[i]; + loop.insert(nodes[index]); + if (index == root_index) break; } loops.insert(loop); @@ -170,42 +230,24 @@ struct TopoSort return; } - if (marked_cells.count(n)) + if (marked_cells[root_index]) return; - if (!database.at(n).empty()) - { + if (!edges[root_index].empty()) { if (analyze_loops) - active_stack.push_back(n); - active_cells.insert(n); + active_stack.push_back(root_index); + active_cells[root_index] = true; - for (auto &left_n : database.at(n)) + for (int left_n : edges[root_index]) sort_worker(left_n, marked_cells, active_cells, active_stack); if (analyze_loops) active_stack.pop_back(); - active_cells.erase(n); + active_cells[root_index] = false; } - marked_cells.insert(n); - sorted.push_back(n); - } - - bool sort() - { - loops.clear(); - sorted.clear(); - found_loops = false; - - std::set marked_cells; - std::set active_cells; - std::vector active_stack; - - for (auto &it : database) - sort_worker(it.first, marked_cells, active_cells, active_stack); - - log_assert(GetSize(sorted) == GetSize(database)); - return !found_loops; + marked_cells[root_index] = true; + sorted.push_back(nodes[root_index]); } }; diff --git a/passes/cmds/glift.cc b/passes/cmds/glift.cc index 439ded07685..faa4289e3a9 100644 --- a/passes/cmds/glift.cc +++ b/passes/cmds/glift.cc @@ -582,7 +582,7 @@ struct GliftPass : public Pass { for (auto cell : module->selected_cells()) { RTLIL::Module *tpl = design->module(cell->type); if (tpl != nullptr) { - if (topo_modules.database.count(tpl) == 0) + if (!topo_modules.has_edges(tpl)) worklist.push_back(tpl); topo_modules.edge(tpl, module); non_top_modules.insert(cell->type); diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 46773a344b1..7331d72a6fd 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -424,13 +424,18 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons for (auto &bit : sig) outbit_to_cell[bit].insert(cell); } - cells.node(cell); } - for (auto &it_right : cell_to_inbit) - for (auto &it_sigbit : it_right.second) - for (auto &it_left : outbit_to_cell[it_sigbit]) - cells.edge(it_left, it_right.first); + // Build the graph for the topological sort. + for (auto &it_right : cell_to_inbit) { + const int r_index = cells.node(it_right.first); + for (auto &it_sigbit : it_right.second) { + for (auto &it_left : outbit_to_cell[it_sigbit]) { + const int l_index = cells.node(it_left); + cells.edge(l_index, r_index); + } + } + } cells.sort(); diff --git a/passes/opt/share.cc b/passes/opt/share.cc index abef719370b..586bd9dfe9d 100644 --- a/passes/opt/share.cc +++ b/passes/opt/share.cc @@ -1032,7 +1032,7 @@ struct ShareWorker } bool found_scc = !toposort.sort(); - topo_cell_drivers = std::move(toposort.database); + topo_cell_drivers = toposort.get_database(); if (found_scc && toposort.analyze_loops) for (auto &loop : toposort.loops) { diff --git a/passes/techmap/flatten.cc b/passes/techmap/flatten.cc index 7e6df5d2c1f..f49589b826c 100644 --- a/passes/techmap/flatten.cc +++ b/passes/techmap/flatten.cc @@ -312,7 +312,7 @@ struct FlattenPass : public Pass { for (auto cell : module->selected_cells()) { RTLIL::Module *tpl = design->module(cell->type); if (tpl != nullptr) { - if (topo_modules.database.count(tpl) == 0) + if (!topo_modules.has_edges(tpl)) worklist.insert(tpl); topo_modules.edge(tpl, module); } From b9745f638b0a2ee4fd97096af7bce0198aedd8be Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Wed, 20 Sep 2023 16:20:08 -0700 Subject: [PATCH 055/173] Remove extraneous "public:". --- kernel/utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/utils.h b/kernel/utils.h index e452f380e63..4679a23f2b9 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -140,7 +140,6 @@ template , typename OPS = hash_ops> cla std::vector sorted; std::set> loops; - public: TopoSort() : indirect_cmp(nodes) { analyze_loops = true; @@ -213,6 +212,7 @@ template , typename OPS = hash_ops> cla bool found_loops; std::vector nodes; const IndirectCmp indirect_cmp; + void sort_worker(const int root_index, std::vector &marked_cells, std::vector &active_cells, std::vector &active_stack) { if (active_cells[root_index]) { From aa06809d6483abe98ab270f093968cab5838d51b Mon Sep 17 00:00:00 2001 From: Ethan Mahintorabi Date: Mon, 18 Sep 2023 21:38:50 +0000 Subject: [PATCH 056/173] rtlil: Speeds up Yosys by 17% This PR speeds up by roughly 17% across a wide spectrum of designs tested at Google. Particularly for the mux generation pass. Co-authored-by: Rasmus Larsen Signed-off-by: Ethan Mahintorabi --- kernel/rtlil.cc | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 51d02091308..1b57af60acb 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4031,16 +4031,20 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec unpack(); other->unpack(); + dict pattern_to_with; for (int i = 0; i < GetSize(pattern.bits_); i++) { if (pattern.bits_[i].wire != NULL) { - for (int j = 0; j < GetSize(bits_); j++) { - if (bits_[j] == pattern.bits_[i]) { - other->bits_[j] = with.bits_[i]; - } - } + pattern_to_with.emplace(pattern.bits_[i], i); } } + for (int j = 0; j < GetSize(bits_); j++) { + auto it = pattern_to_with.find(bits_[j]); + if (it != pattern_to_with.end()) { + other->bits_[j] = with.bits_[it->second]; + } + } + other->check(); } From 9ed38bf9b662b36852271671f2a73ed659b00331 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Thu, 21 Sep 2023 02:46:49 -0700 Subject: [PATCH 057/173] Speed up the autoname pass by 3x. (#3945) * Speed up the autoname pass by 2x. This is accomplished by only constructing IdString objects for plain strings that have a higher score. * Defer creating IdStrings even further. This increases the speedup to 3x. --- passes/cmds/autoname.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/passes/cmds/autoname.cc b/passes/cmds/autoname.cc index 6019c61534f..737bd3e58be 100644 --- a/passes/cmds/autoname.cc +++ b/passes/cmds/autoname.cc @@ -24,8 +24,8 @@ PRIVATE_NAMESPACE_BEGIN int autoname_worker(Module *module, const dict& wire_score) { - dict> proposed_cell_names; - dict> proposed_wire_names; + dict> proposed_cell_names; + dict> proposed_wire_names; int best_score = -1; for (auto cell : module->selected_cells()) { @@ -36,7 +36,7 @@ int autoname_worker(Module *module, const dict& wire_score) if (bit.wire != nullptr && bit.wire->name[0] != '$') { if (suffix.empty()) suffix = stringf("_%s_%s", log_id(cell->type), log_id(conn.first)); - IdString new_name(bit.wire->name.str() + suffix); + string new_name(bit.wire->name.str() + suffix); int score = wire_score.at(bit.wire); if (cell->output(conn.first)) score = 0; score = 10000*score + new_name.size(); @@ -54,7 +54,7 @@ int autoname_worker(Module *module, const dict& wire_score) if (bit.wire != nullptr && bit.wire->name[0] == '$' && !bit.wire->port_id) { if (suffix.empty()) suffix = stringf("_%s", log_id(conn.first)); - IdString new_name(cell->name.str() + suffix); + string new_name(cell->name.str() + suffix); int score = wire_score.at(bit.wire); if (cell->output(conn.first)) score = 0; score = 10000*score + new_name.size(); @@ -71,7 +71,7 @@ int autoname_worker(Module *module, const dict& wire_score) for (auto &it : proposed_cell_names) { if (best_score*2 < it.second.first) continue; - IdString n = module->uniquify(it.second.second); + IdString n = module->uniquify(IdString(it.second.second)); log_debug("Rename cell %s in %s to %s.\n", log_id(it.first), log_id(module), log_id(n)); module->rename(it.first, n); } @@ -79,7 +79,7 @@ int autoname_worker(Module *module, const dict& wire_score) for (auto &it : proposed_wire_names) { if (best_score*2 < it.second.first) continue; - IdString n = module->uniquify(it.second.second); + IdString n = module->uniquify(IdString(it.second.second)); log_debug("Rename wire %s in %s to %s.\n", log_id(it.first), log_id(module), log_id(n)); module->rename(it.first, n); } From 934c82254d8abd33ee8827b200ff005868737f74 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 22 Sep 2023 00:14:51 +0000 Subject: [PATCH 058/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a75af96b555..77f7b80fadf 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+56 +YOSYS_VER := 0.33+65 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From fedd12261fc6e3828baf6025a0d3af1931495eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 18 Sep 2023 18:56:30 +0200 Subject: [PATCH 059/173] booth: Move away from explicit `Wire` pointers To represent intermediate signals use the `SigBit`/`SigSpec` classes as is customary in the Yosys codebase. Do not pass around `Wire` pointers unless we have special reason to. --- passes/techmap/booth.cc | 442 ++++++++++++++++++---------------------- 1 file changed, 194 insertions(+), 248 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index e749168522d..fe9c1cec6c0 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -94,7 +94,7 @@ struct BoothPassWorker { } // Unary gate - RTLIL::Wire *mk_ugate1(const RTLIL::IdString &red_typ, std::string &name, RTLIL::Wire *ip1, std::string &op_name) + RTLIL::Wire *mk_ugate1(const RTLIL::IdString &red_typ, std::string &name, SigBit ip1, std::string &op_name) { std::string op_wire_name; if (op_name.empty()) @@ -112,7 +112,7 @@ struct BoothPassWorker { } // Binary gate - RTLIL::Wire *mk_ugate2(const RTLIL::IdString &red_typ, std::string &name, RTLIL::Wire *ip1, RTLIL::Wire *ip2, std::string &op_name) + RTLIL::Wire *mk_ugate2(const RTLIL::IdString &red_typ, std::string &name, SigBit ip1, SigBit ip2, std::string &op_name) { auto g = module->addCell(new_id(name, __LINE__, ""), red_typ); std::string op_wire_name; @@ -135,7 +135,7 @@ struct BoothPassWorker { } // Booth unsigned decoder lsb - void BuildBur4d_lsb(std::string &name, RTLIL::Wire *lsb_i, RTLIL::Wire *one_i, RTLIL::Wire *s_i, RTLIL::Wire *&ppij_o, + void BuildBur4d_lsb(std::string &name, SigBit lsb_i, SigBit one_i, SigBit s_i, SigBit &ppij_o, std::string op_wire_name) { std::string empty; @@ -144,8 +144,8 @@ struct BoothPassWorker { } // Booth unsigned radix4 decoder - void BuildBur4d_n(std::string &name, RTLIL::Wire *yn_i, RTLIL::Wire *ynm1_i, RTLIL::Wire *one_i, RTLIL::Wire *two_i, RTLIL::Wire *s_i, - RTLIL::Wire *&ppij_o) + void BuildBur4d_n(std::string &name, SigBit yn_i, SigBit ynm1_i, SigBit one_i, SigBit two_i, SigBit s_i, + SigBit &ppij_o) { // ppij = ((yn & one) | (ynm1 & two)) ^ s; std::string empty; @@ -156,7 +156,7 @@ struct BoothPassWorker { } // Booth unsigned radix4 decoder - void BuildBur4d_msb(std::string &name, RTLIL::Wire *msb_i, RTLIL::Wire *two_i, RTLIL::Wire *s_i, RTLIL::Wire *&ppij_o) + void BuildBur4d_msb(std::string &name, SigBit msb_i, SigBit two_i, SigBit s_i, SigBit &ppij_o) { // ppij = (msb & two) ^ s; std::string empty; @@ -165,7 +165,7 @@ struct BoothPassWorker { } // half adder, used in CPA - void BuildHa(std::string &name, RTLIL::Wire *a_i, RTLIL::Wire *b_i, RTLIL::Wire *&s_o, RTLIL::Wire *&c_o) + void BuildHa(std::string &name, SigBit a_i, SigBit b_i, SigBit &s_o, SigBit &c_o) { std::string empty; s_o = mk_ugate2(ID($xor), name, a_i, b_i, empty); @@ -173,9 +173,8 @@ struct BoothPassWorker { } // Booth unsigned radix 4 encoder - void BuildBur4e(std::string &name, RTLIL::Wire *y0_i, RTLIL::Wire *y1_i, RTLIL::Wire *y2_i, - - RTLIL::Wire *&one_o, RTLIL::Wire *&two_o, RTLIL::Wire *&s_o, RTLIL::Wire *&sb_o) + void BuildBur4e(std::string &name, SigBit y0_i, SigBit y1_i, SigBit y2_i, + SigBit &one_o, SigBit &two_o, SigBit &s_o, SigBit &sb_o) { std::string empty; @@ -186,11 +185,10 @@ struct BoothPassWorker { two_o = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, inv_y1_xor_y2, one_o, empty), empty); } - void BuildBr4e(std::string &name, RTLIL::Wire *y2_m1_i, - RTLIL::Wire *y2_i, // y2i - RTLIL::Wire *y2_p1_i, - - RTLIL::Wire *&negi_o, RTLIL::Wire *&twoi_n_o, RTLIL::Wire *&onei_n_o, RTLIL::Wire *&cori_o) + void BuildBr4e(std::string &name, SigBit y2_m1_i, + SigBit y2_i, // y2i + SigBit y2_p1_i, + SigBit &negi_o, SigBit &twoi_n_o, SigBit &onei_n_o, SigBit &cori_o) { std::string empty; @@ -217,9 +215,8 @@ struct BoothPassWorker { // // signed booth radix 4 decoder // - void BuildBr4d(std::string &name, RTLIL::Wire *nxj_m1_i, RTLIL::Wire *twoi_n_i, RTLIL::Wire *xj_i, RTLIL::Wire *negi_i, RTLIL::Wire *onei_n_i, - - RTLIL::Wire *&ppij_o, RTLIL::Wire *&nxj_o) + void BuildBr4d(std::string &name, SigBit nxj_m1_i, SigBit twoi_n_i, SigBit xj_i, SigBit negi_i, SigBit onei_n_i, + SigBit &ppij_o, SigBit &nxj_o) { std::string empty; @@ -227,8 +224,8 @@ struct BoothPassWorker { // nxj_o = xnj_in, // ppij = ~( (nxj_m1_i | twoi_n_i) & (nxj_int | onei_n_i)); nxj_o = mk_ugate2(ID($xnor), name, xj_i, negi_i, empty); - RTLIL::Wire *or1 = mk_ugate2(ID($or), name, nxj_m1_i, twoi_n_i, empty); - RTLIL::Wire *or2 = mk_ugate2(ID($or), name, nxj_o, onei_n_i, empty); + SigBit or1 = mk_ugate2(ID($or), name, nxj_m1_i, twoi_n_i, empty); + SigBit or2 = mk_ugate2(ID($or), name, nxj_o, onei_n_i, empty); ppij_o = mk_ugate1(ID($not), name, mk_ugate2(ID($and), name, or1, or2, empty), empty); } @@ -237,12 +234,9 @@ struct BoothPassWorker { using non-booth encoded logic. We can save a booth encoder for the first couple of bits. */ - void BuildBoothQ1(std::string &name, RTLIL::Wire *negi_i, RTLIL::Wire *cori_i, RTLIL::Wire *x0_i, RTLIL::Wire *x1_i, RTLIL::Wire *y0_i, - RTLIL::Wire *y1_i, - - RTLIL::Wire *&nxj_o, RTLIL::Wire *&cor_o, RTLIL::Wire *&pp0_o, RTLIL::Wire *&pp1_o - - ) + void BuildBoothQ1(std::string &name, SigBit negi_i, SigBit cori_i, SigBit x0_i, SigBit x1_i, SigBit y0_i, + SigBit y1_i, + SigBit &nxj_o, SigBit &cor_o, SigBit &pp0_o, SigBit &pp1_o) { /* assign NXJO = ~(X1 ^ NEGI); @@ -258,11 +252,11 @@ struct BoothPassWorker { std::string empty; nxj_o = mk_ugate2(ID($xnor), name, x1_i, negi_i, empty); pp0_o = mk_ugate2(ID($and), name, x0_i, y0_i, empty); - RTLIL::Wire *pp1_1_int = mk_ugate2(ID($and), name, x1_i, y0_i, empty); - RTLIL::Wire *pp1_2_int = mk_ugate2(ID($and), name, x0_i, y1_i, empty); + SigBit pp1_1_int = mk_ugate2(ID($and), name, x1_i, y0_i, empty); + SigBit pp1_2_int = mk_ugate2(ID($and), name, x0_i, y1_i, empty); pp1_o = mk_ugate2(ID($xor), name, pp1_1_int, pp1_2_int, empty); - RTLIL::Wire *pp1_nor_pp0 = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, pp1_o, pp0_o, empty), empty); + SigBit pp1_nor_pp0 = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, pp1_o, pp0_o, empty), empty); cor_o = mk_ugate2(ID($and), name, pp1_nor_pp0, cori_i, empty); } @@ -355,13 +349,13 @@ struct BoothPassWorker { buf->setPort(ID::Y, SigSpec(Y)); if (is_signed == false) /* unsigned multiplier */ - CreateBoothUMult(module, x_sz_revised, y_sz_revised, required_op_size, + CreateBoothUMult(module, expanded_A, // multiplicand expanded_B, // multiplier(scanned) expanded_Y // result ); else /*signed multiplier */ - CreateBoothSMult(module, x_sz_revised, y_sz_revised, required_op_size, + CreateBoothSMult(module, expanded_A, // multiplicand expanded_B, // multiplier(scanned) expanded_Y // result (sized) @@ -382,19 +376,17 @@ struct BoothPassWorker { extra row of decoders and extended multiplier */ - void CreateBoothUMult(RTLIL::Module *module, int x_sz, int y_sz, int z_sz, - RTLIL::Wire *X, // multiplicand - RTLIL::Wire *Y, // multiplier - RTLIL::Wire *Z) + void CreateBoothUMult(RTLIL::Module *module, + SigSpec X, // multiplicand + SigSpec Y, // multiplier + SigSpec Z) { // result + int x_sz = X.size(), z_sz = Z.size(); - std::vector one_int; - std::vector two_int; - std::vector s_int; - std::vector sb_int; + SigSpec one_int, two_int, s_int, sb_int; int encoder_count = 0; - BuildBoothUMultEncoders(Y, y_sz, one_int, two_int, s_int, sb_int, module, encoder_count); + BuildBoothUMultEncoders(Y, one_int, two_int, s_int, sb_int, module, encoder_count); // Build the decoder rows // format of each Partial product to be passed to CSA @@ -404,31 +396,10 @@ struct BoothPassWorker { // Shift // Sign bit to be added // - std::vector, int, RTLIL::Wire *>> ppij_int; - - static int constant_ix; - constant_ix++; - std::string buf_name = "constant_buf_" + std::to_string(constant_ix); - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - RTLIL::Wire *constant_one = module->addWire(new_id(buf_name, __LINE__, ""), 1); - buf->setPort(ID::A, State::S1); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, constant_one); - - constant_ix++; - buf_name = "constant_buf_" + std::to_string(constant_ix); - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - RTLIL::Wire *constant_zero = module->addWire(new_id(buf_name, __LINE__, ""), 1); - buf->setPort(ID::A, State::S0); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, constant_zero); + std::vector> ppij_int; // Row 0: special case 1. Format S/.S.S.C.Data - std::vector ppij_row_0; + SigSpec ppij_row_0; BuildBoothUMultDecoderRow0(module, X, s_int, sb_int, one_int, two_int, ppij_row_0); // data, shift, sign @@ -436,11 +407,11 @@ struct BoothPassWorker { for (int i = 1; i < encoder_count - 2; i++) { // format 1,S.Data.shift = encoder_ix*2,sign = sb_int[i] - std::vector ppij_row_n; + SigSpec ppij_row_n; BuildBoothUMultDecoderRowN(module, X, // multiplicand - one_int[i], two_int[i], s_int[i], sb_int[i], ppij_row_n, constant_one, i, + one_int[i], two_int[i], s_int[i], sb_int[i], ppij_row_n, i, false, // include sign false // include constant ); @@ -450,18 +421,18 @@ struct BoothPassWorker { // Build second to last row // format S/,Data + sign bit - std::vector ppij_row_em1; + SigSpec ppij_row_em1; BuildBoothUMultDecoderRowN(module, X, one_int[encoder_count - 2], two_int[encoder_count - 2], s_int[encoder_count - 2], - sb_int[encoder_count - 2], ppij_row_em1, constant_one, encoder_count - 2, + sb_int[encoder_count - 2], ppij_row_em1, encoder_count - 2, false, // include sign true // no constant ); ppij_int.push_back(std::make_tuple(ppij_row_em1, (encoder_count - 2) * 2, s_int[encoder_count - 2])); // Build last row // format Data + sign bit - std::vector ppij_row_e; + SigSpec ppij_row_e; BuildBoothUMultDecoderRowN(module, X, one_int[encoder_count - 1], two_int[encoder_count - 1], s_int[encoder_count - 1], - sb_int[encoder_count - 1], ppij_row_e, constant_one, encoder_count - 1, + sb_int[encoder_count - 1], ppij_row_e, encoder_count - 1, true, // no sign true // no constant ); @@ -471,13 +442,13 @@ struct BoothPassWorker { // DebugDumpPP(ppij_int); // Summation of Partial Products (Wallace Tree) - std::vector> aligned_pp; + std::vector aligned_pp; aligned_pp.resize(encoder_count + 1); // make an entirely redundant row // just for sign bit in lsb. (We then filter this out). // resize all to be same size as z for (int i = 0; i < encoder_count + 1; i++) - aligned_pp[i].resize(z_sz); + aligned_pp[i].extend_u0(z_sz); AlignPP(x_sz, z_sz, ppij_int, aligned_pp); @@ -485,8 +456,8 @@ struct BoothPassWorker { // Later on yosys will clean up unused constants // DebugDumpAlignPP(aligned_pp); - std::vector s_vec; - std::vector c_vec; + SigSpec s_vec; + SigSpec c_vec; std::vector> debug_csa_trees; debug_csa_trees.resize(z_sz); @@ -504,9 +475,9 @@ struct BoothPassWorker { */ void BuildBoothUMultDecoderRow0(RTLIL::Module *module, - RTLIL::Wire *X, // multiplicand - std::vector &s_int, std::vector &sb_int, std::vector &one_int, - std::vector &two_int, std::vector &ppij_vec) + SigSpec X, // multiplicand + SigSpec s_int, SigSpec sb_int, SigSpec one_int, + SigSpec two_int, SigSpec &ppij_vec) { (void)module; int x_sz = GetSize(X); @@ -514,73 +485,72 @@ struct BoothPassWorker { // lsb std::string dec_name = "row0_lsb_dec"; - RTLIL::Wire *ppij; + SigBit ppij; std::string ppij_name = "ppij_0_0"; - BuildBur4d_lsb(dec_name, mk_wireFromSigSpec(SigSpec(X, 0, 1)), one_int[0], s_int[0], ppij, ppij_name); - ppij_vec.push_back(ppij); + BuildBur4d_lsb(dec_name, X[0], one_int[0], s_int[0], ppij, ppij_name); + ppij_vec.append(ppij); // 1..xsize -1 for (int i = 1; i < x_sz; i++) { dec_name = "row0_dec_" + std::to_string(i); - RTLIL::Wire *ppij; - BuildBur4d_n(dec_name, mk_wireFromSigSpec(SigSpec(X, i, 1)), mk_wireFromSigSpec(SigSpec(X, i - 1, 1)), one_int[0], two_int[0], + SigBit ppij; + BuildBur4d_n(dec_name, X[i], X[i - 1], one_int[0], two_int[0], s_int[0], ppij); - ppij_vec.push_back(ppij); + ppij_vec.append(ppij); } // The redundant bit. Duplicate decoding of last bit. dec_name = "row0_dec_msb"; - BuildBur4d_msb(dec_name, mk_wireFromSigSpec(SigSpec(X, x_sz - 1, 1)), two_int[0], s_int[0], ppij); - ppij_vec.push_back(ppij); + BuildBur4d_msb(dec_name, X[x_sz - 1], two_int[0], s_int[0], ppij); + ppij_vec.append(ppij); // append the sign bits - ppij_vec.push_back(s_int[0]); - ppij_vec.push_back(s_int[0]); - ppij_vec.push_back(sb_int[0]); + ppij_vec.append(s_int[0]); + ppij_vec.append(s_int[0]); + ppij_vec.append(sb_int[0]); } // Build a generic row of decoders. void BuildBoothUMultDecoderRowN(RTLIL::Module *module, - RTLIL::Wire *X, // multiplicand - RTLIL::Wire *one_int, RTLIL::Wire *two_int, RTLIL::Wire *s_int, RTLIL::Wire *sb_int, - std::vector &ppij_vec, RTLIL::Wire *constant_one, int row_ix, bool no_sign, bool no_constant) + SigSpec X, // multiplicand + SigSpec one_int, SigSpec two_int, SigSpec s_int, SigSpec sb_int, + SigSpec &ppij_vec, int row_ix, bool no_sign, bool no_constant) { (void)module; int x_sz = GetSize(X); // lsb std::string ppij_name = "ppij_" + std::to_string(row_ix) + "_0"; - RTLIL::Wire *ppij = nullptr; + SigBit ppij; std::string empty; std::string dec_name = "row" + std::to_string(row_ix) + "_lsb_dec"; - BuildBur4d_lsb(dec_name, mk_wireFromSigSpec(SigSpec(X, 0, 1)), one_int, s_int, ppij, empty); + BuildBur4d_lsb(dec_name, X[0], one_int, s_int, ppij, empty); - ppij_vec.push_back(ppij); + ppij_vec.append(ppij); // core bits for (int i = 1; i < x_sz; i++) { dec_name = "row_" + std::to_string(row_ix) + "_dec_" + std::to_string(i); - RTLIL::Wire *ppij = nullptr; - BuildBur4d_n(dec_name, mk_wireFromSigSpec(SigSpec(X, i, 1)), mk_wireFromSigSpec(SigSpec(X, i - 1, 1)), one_int, two_int, - s_int, ppij); - ppij_vec.push_back(ppij); + BuildBur4d_n(dec_name, X[i], X[i - 1], + one_int, two_int, s_int, ppij); + ppij_vec.append(ppij); } // redundant bit dec_name = "row_dec_red"; - BuildBur4d_msb(dec_name, mk_wireFromSigSpec(SigSpec(X, x_sz - 1, 1)), two_int, s_int, ppij); - ppij_vec.push_back(ppij); + BuildBur4d_msb(dec_name, X[x_sz - 1], two_int, s_int, ppij); + ppij_vec.append(ppij); // sign bit if (no_sign == false) // if no sign is false then make a sign bit - ppij_vec.push_back(sb_int); + ppij_vec.append(sb_int); // constant bit if (no_constant == false) { // if non constant is false make a constant bit - ppij_vec.push_back(constant_one); + ppij_vec.append(State::S1); } } @@ -663,8 +633,8 @@ struct BoothPassWorker { } } - void BuildCSATree(RTLIL::Module *module, std::vector> &bits_to_reduce, std::vector &s_vec, - std::vector &c_vec, std::vector> &debug_csa_trees) + void BuildCSATree(RTLIL::Module *module, std::vector &bits_to_reduce, SigSpec &s_vec, + SigSpec &c_vec, std::vector> &debug_csa_trees) { if (!(bits_to_reduce.size() > 0)) @@ -672,24 +642,24 @@ struct BoothPassWorker { int column_size = bits_to_reduce[0].size(); int row_size = bits_to_reduce.size(); - std::vector carry_bits_to_add_to_next_column; + SigSpec carry_bits_to_add_to_next_column; for (int column_ix = 0; column_ix < column_size; column_ix++) { // get the bits in this column. - std::vector column_bits; + SigSpec column_bits; for (int row_ix = 0; row_ix < row_size; row_ix++) { - if (bits_to_reduce[row_ix].at(column_ix)) - column_bits.push_back(bits_to_reduce[row_ix].at(column_ix)); + if (bits_to_reduce[row_ix][column_ix].wire) + column_bits.append(bits_to_reduce[row_ix][column_ix]); } for (auto c : carry_bits_to_add_to_next_column) { #ifdef DEBUG_CSA printf("\t Propagating column bit %s to column %d from column %d\n", c->name.c_str(), column_ix, column_ix - 1); #endif - column_bits.push_back(c); + column_bits.append(c); } - carry_bits_to_add_to_next_column.resize(0); + carry_bits_to_add_to_next_column = {}; #ifdef DEBUG_CSA printf("Column %d Reducing %d bits\n", column_ix, column_bits.size()); @@ -699,16 +669,15 @@ struct BoothPassWorker { printf("\n"); #endif - RTLIL::Wire *s = nullptr; - RTLIL::Wire *c = nullptr; + SigBit s, c; #ifdef DEBUG_CSA int csa_count_before = debug_csa_trees[column_ix].size(); #endif ReduceBits(module, column_ix, column_bits, s, c, carry_bits_to_add_to_next_column, debug_csa_trees); - s_vec.push_back(s); - c_vec.push_back(c); + s_vec.append(s); + c_vec.append(c); #ifdef DEBUG_CSA int csa_count_after = debug_csa_trees[column_ix].size(); @@ -738,8 +707,8 @@ struct BoothPassWorker { Pad out rows with zeros and left the opt pass clean them up. */ - void AlignPP(int x_sz, int z_sz, std::vector, int, RTLIL::Wire *>> &ppij_int, - std::vector> &aligned_pp) + void AlignPP(int x_sz, int z_sz, std::vector> &ppij_int, + std::vector &aligned_pp) { unsigned aligned_pp_ix = aligned_pp.size() - 1; @@ -748,7 +717,7 @@ struct BoothPassWorker { for (unsigned i = 0; i < aligned_pp.size(); i++) { for (int j = 0; j < z_sz; j++) { - aligned_pp[i][j] = nullptr; + aligned_pp[i][j] = State::S0; } } @@ -758,21 +727,19 @@ struct BoothPassWorker { // in first column of the last partial product // which is at index corresponding to size of multiplicand { - RTLIL::Wire *prior_row_sign = nullptr; - prior_row_sign = get<2>(ppij_int[aligned_pp_ix - 1]); - if (prior_row_sign) { + SigBit prior_row_sign = get<2>(ppij_int[aligned_pp_ix - 1]); + //if (prior_row_sign) { log_assert(aligned_pp_ix < aligned_pp.size()); log_assert(x_sz - 1 < (int)(aligned_pp[aligned_pp_ix].size())); aligned_pp[aligned_pp_ix][x_sz - 1] = prior_row_sign; - } + //} } for (int row_ix = aligned_pp_ix - 1; row_ix >= 0; row_ix--) { int shift_amount = get<1>(ppij_int[row_ix]); - RTLIL::Wire *prior_row_sign = nullptr; // copy in data - unsigned copy_ix = shift_amount; + int copy_ix = shift_amount; for (auto w : get<0>(ppij_int[row_ix])) { if (copy_ix < aligned_pp[row_ix].size()) { aligned_pp[row_ix][copy_ix] = w; @@ -786,7 +753,7 @@ struct BoothPassWorker { // the destination of the sign bit is the (row_ix -1)*2 // eg destination for sign bit for row 0 is 0. // eg destination for sign bit for row 1 is 1 - prior_row_sign = get<2>(ppij_int[row_ix - 1]); + SigBit prior_row_sign = get<2>(ppij_int[row_ix - 1]); copy_ix = (row_ix - 1) * 2; aligned_pp[row_ix][copy_ix] = prior_row_sign; } @@ -797,32 +764,23 @@ struct BoothPassWorker { Build a Carry Propagate Adder ----------------------------- First build the sum and carry vectors to be added. - Axioms: - c_vec.size() == s_vec.size() - result.size() == s_vec.size() + 2; (assume result is reserved to hold correct size) */ - void BuildCPA(RTLIL::Module *module, std::vector &s_vec, std::vector &c_vec, RTLIL::Wire *result) + void BuildCPA(RTLIL::Module *module, SigSpec s_vec, SigSpec c_vec, SigSpec result) { - static int cpa_id; cpa_id++; - RTLIL::Wire *carry = nullptr; - - log_assert(s_vec.size() == c_vec.size()); + log_assert(c_vec.size() == s_vec.size()); + // TODO: doesn't pass + //log_assert(result.size() == s_vec.size() + 2); - for (unsigned n = 0; n < s_vec.size(); n++) { + SigBit carry; + for (int n = 0; n < s_vec.size(); n++) { std::string carry_name; // Base Case: Bit 0 is sum 0 if (n == 0) { - std::string buf_name = "base_buf_" + std::to_string(cpa_id) + "_" + std::to_string(n); - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, s_vec[0]); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, false); - buf->setPort(ID::Y, SigSpec(result, 0, 1)); + module->addBufGate(NEW_ID_SUFFIX(stringf("base_buf_%d_%d", cpa_id, n)), s_vec[0], result[0]); #ifdef DEBUG_CPA printf("CPA bit [%d] Cell %s IP 0 %s \n", n, buf->name.c_str(), s_vec[0]->name.c_str()); @@ -835,10 +793,9 @@ struct BoothPassWorker { // else if (n == 1) { std::string ha_name = "cpa_" + std::to_string(cpa_id) + "_ha_" + std::to_string(n); - RTLIL::Wire *ha_op; + SigBit ha_op; BuildHa(ha_name, s_vec[n], c_vec[n - 1], ha_op, carry); - - module->connect(ha_op, SigSpec(result, n, 1)); + module->connect(result[n], ha_op); #ifdef DEBUG_CPA printf("CPA bit [%d] Cell %s IPs [%s] [%s] \n", n, ha_cell->name.c_str(), s_vec[n]->name.c_str(), @@ -847,9 +804,10 @@ struct BoothPassWorker { } // End Case - else if (n == (unsigned)((s_vec.size() - 1))) { + else if (n == s_vec.size() - 1) { // Make the carry results.. Two extra bits after fa. std::string fa_name = "cpa_" + std::to_string(cpa_id) + "_fa_" + std::to_string(n); + auto fa_cell = module->addCell(new_id(fa_name, __LINE__, ""), ID($fa)); fa_cell->setParam(ID::WIDTH, 1); carry_name = "cpa_" + std::to_string(cpa_id) + "carry_" + std::to_string(n); @@ -857,7 +815,7 @@ struct BoothPassWorker { fa_cell->setPort(ID::B, c_vec[n - 1]); fa_cell->setPort(ID::C, carry); // wire in result and carry out - fa_cell->setPort(ID::Y, SigSpec(result, n, 1)); + fa_cell->setPort(ID::Y, result[n]); // make a new carry bit for carry out... carry = module->addWire(new_id(carry_name, __LINE__, ""), 1); @@ -867,16 +825,16 @@ struct BoothPassWorker { printf("CPA bit [%d] Cell %s IPs [%s] [%s] [%s]\n", n, fa_cell->name.c_str(), s_vec[n]->name.c_str(), c_vec[n - 1]->name.c_str(), carry->name.c_str()); #endif - if (n + 1 < (unsigned)(GetSize(result))) { + if (n + 1 < GetSize(result)) { // Now make a half adder: c_vec[n] = carry std::string ha_name = "cpa_" + std::to_string(cpa_id) + "_ha_" + std::to_string(n); - RTLIL::Wire *ha_sum; - RTLIL::Wire *ha_carry; + SigBit ha_sum; + SigBit ha_carry; BuildHa(ha_name, c_vec[n], carry, ha_sum, ha_carry); - if (n + 1 < (unsigned)GetSize(result)) - module->connect(ha_sum, SigSpec(result, n + 1, 1)); - if (n + 2 < (unsigned)GetSize(result)) - module->connect(ha_carry, SigSpec(result, n + 2, 1)); + if (n + 1 < GetSize(result)) + module->connect(result[n + 1], ha_sum); + if (n + 2 < GetSize(result)) + module->connect(result[n + 2], ha_carry); } } // Step case @@ -890,7 +848,7 @@ struct BoothPassWorker { fa_cell->setPort(ID::B, c_vec[n - 1]); fa_cell->setPort(ID::C, carry); // wire in result and carry out - fa_cell->setPort(ID::Y, SigSpec(result, n, 1)); + fa_cell->setPort(ID::Y, result[n]); // make a new carry bit for carry out... carry = module->addWire(new_id(carry_name, __LINE__, ""), 1); fa_cell->setPort(ID::X, carry); @@ -907,8 +865,8 @@ struct BoothPassWorker { // Pass the carry bits from each csa to the next // column for summation. - void ReduceBits(RTLIL::Module *module, int column_ix, std::vector &column_bits, RTLIL::Wire *&s_result, RTLIL::Wire *&c_result, - std::vector &carry_bits_to_sum, std::vector> &debug_csa_trees) + void ReduceBits(RTLIL::Module *module, int column_ix, SigSpec column_bits, SigBit &s_result, SigBit &c_result, + SigSpec &carry_bits_to_sum, std::vector> &debug_csa_trees) { int csa_ix = 0; @@ -918,12 +876,12 @@ struct BoothPassWorker { unique_id++; if (column_size > 0) { - unsigned var_ix = 0; - std::vector first_csa_ips; + int var_ix = 0; + SigSpec first_csa_ips; // get the first 3 inputs, if possible for (var_ix = 0; var_ix < column_bits.size() && first_csa_ips.size() != 3; var_ix++) { - if (column_bits[var_ix]) - first_csa_ips.push_back(column_bits[var_ix]); + if (column_bits[var_ix].is_wire()) + first_csa_ips.append(column_bits[var_ix]); } if (first_csa_ips.size() > 0) { @@ -961,16 +919,16 @@ struct BoothPassWorker { c_result = c_wire; if (var_ix <= column_bits.size() - 1) - carry_bits_to_sum.push_back(c_wire); + carry_bits_to_sum.append(c_wire); // Now build the rest of the tree if we can while (var_ix <= column_bits.size() - 1) { - std::vector csa_ips; + SigSpec csa_ips; // get the next two variables to sum for (; var_ix <= column_bits.size() - 1 && csa_ips.size() < 2;) { // skip any empty bits - if (column_bits[var_ix] != nullptr) - csa_ips.push_back(column_bits[var_ix]); + if (column_bits[var_ix].is_wire()) + csa_ips.append(column_bits[var_ix]); var_ix++; } @@ -993,7 +951,7 @@ struct BoothPassWorker { c_wire = module->addWire(new_id(carry_wire_name, __LINE__, ""), 1); if (var_ix <= column_bits.size() - 1) - carry_bits_to_sum.push_back(c_wire); + carry_bits_to_sum.append(c_wire); sum_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_s"; s_wire = module->addWire(new_id(sum_wire_name, __LINE__, ""), 1); @@ -1009,28 +967,30 @@ struct BoothPassWorker { } } - void BuildBoothUMultEncoders(RTLIL::Wire *Y, int y_sz, std::vector &one_int, std::vector &two_int, - std::vector &s_int, std::vector &sb_int, RTLIL::Module *module, int &encoder_ix) + void BuildBoothUMultEncoders(SigSpec Y, SigSpec &one_int, SigSpec &two_int, + SigSpec &s_int, SigSpec &sb_int, RTLIL::Module *module, int &encoder_ix) { + int y_sz = GetSize(Y); + for (int y_ix = 0; y_ix < y_sz;) { std::string enc_name = "bur_enc_" + std::to_string(encoder_ix) + "_"; std::string two_name = "two_int" + std::to_string(encoder_ix); - two_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); + two_int.append(module->addWire(new_id(two_name, __LINE__, ""), 1)); std::string one_name = "one_int" + std::to_string(encoder_ix); - one_int.push_back(module->addWire(new_id(one_name, __LINE__, ""), 1)); + one_int.append(module->addWire(new_id(one_name, __LINE__, ""), 1)); std::string s_name = "s_int" + std::to_string(encoder_ix); - s_int.push_back(module->addWire(new_id(s_name, __LINE__, ""), 1)); + s_int.append(module->addWire(new_id(s_name, __LINE__, ""), 1)); std::string sb_name = "sb_int" + std::to_string(encoder_ix); - sb_int.push_back(module->addWire(new_id(sb_name, __LINE__, ""), 1)); + sb_int.append(module->addWire(new_id(sb_name, __LINE__, ""), 1)); if (y_ix == 0) { - BuildBur4e(enc_name, mk_wireFromSigSpec(State::S0), mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)), - mk_wireFromSigSpec(SigSpec(Y, y_ix + 1, 1)), one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], + BuildBur4e(enc_name, State::S0, Y[y_ix], + Y[y_ix + 1], one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], sb_int[encoder_ix]); y_ix = y_ix + 1; @@ -1041,39 +1001,37 @@ struct BoothPassWorker { // then add an extra booth encoder bounded by // zeroes to ensure unsigned works. // - RTLIL::Wire *y0_wire; - RTLIL::Wire *y1_wire; - RTLIL::Wire *y2_wire; + SigBit y0, y1, y2; bool need_padded_cell = false; if (y_ix > y_sz - 1) { - y0_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + y0 = State::S0; need_padded_cell = false; } else { - y0_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + y0 = Y[y_ix]; y_ix++; } if (y_ix > y_sz - 1) { need_padded_cell = false; - y1_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + y1 = State::S0; } else { - y1_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + y1 = Y[y_ix]; y_ix++; } if (y_ix > y_sz - 1) { need_padded_cell = false; - y2_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + y2 = State::S0; } else { if (y_ix == y_sz - 1) need_padded_cell = true; else need_padded_cell = false; - y2_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + y2 = Y[y_ix]; - BuildBur4e(enc_name, y0_wire, y1_wire, y2_wire, one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], + BuildBur4e(enc_name, y0, y1, y2, one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], sb_int[encoder_ix]); } @@ -1087,25 +1045,25 @@ struct BoothPassWorker { std::string enc_name = "br_enc_pad" + std::to_string(encoder_ix) + "_"; std::string two_name = "two_int" + std::to_string(encoder_ix); - two_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); + two_int.append(module->addWire(new_id(two_name, __LINE__, ""), 1)); std::string one_name = "one_int" + std::to_string(encoder_ix); - one_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); + one_int.append(module->addWire(new_id(two_name, __LINE__, ""), 1)); std::string s_name = "s_int" + std::to_string(encoder_ix); - s_int.push_back(module->addWire(new_id(s_name, __LINE__, ""), 1)); + s_int.append(module->addWire(new_id(s_name, __LINE__, ""), 1)); std::string sb_name = "sb_int" + std::to_string(encoder_ix); - sb_int.push_back(module->addWire(new_id(sb_name, __LINE__, ""), 1)); + sb_int.append(module->addWire(new_id(sb_name, __LINE__, ""), 1)); - RTLIL::Wire *one_o_int, *two_o_int, *s_o_int, *sb_o_int; - BuildBur4e(enc_name, mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)), mk_wireFromSigSpec(State::S0), - mk_wireFromSigSpec(State::S0), one_o_int, two_o_int, s_o_int, sb_o_int); + SigBit one_o_int, two_o_int, s_o_int, sb_o_int; + BuildBur4e(enc_name, Y[y_ix], State::S0, + State::S0, one_o_int, two_o_int, s_o_int, sb_o_int); - join_wires_with_buffer(one_o_int, one_int[encoder_ix]); - join_wires_with_buffer(two_o_int, two_int[encoder_ix]); - join_wires_with_buffer(s_o_int, s_int[encoder_ix]); - join_wires_with_buffer(sb_o_int, sb_int[encoder_ix]); + module->connect(one_int[encoder_ix], one_o_int); + module->connect(two_int[encoder_ix], two_o_int); + module->connect(s_int[encoder_ix], s_o_int); + module->connect(sb_int[encoder_ix], sb_o_int); y_ix++; encoder_ix++; } @@ -1116,8 +1074,10 @@ struct BoothPassWorker { /* Signed Multiplier */ - void CreateBoothSMult(RTLIL::Module *module, int x_sz, int y_sz, int z_sz, RTLIL::Wire *X, RTLIL::Wire *Y, RTLIL::Wire *Z) + void CreateBoothSMult(RTLIL::Module *module, SigSpec X, SigSpec Y, SigSpec Z) { // product + int x_sz = X.size(), y_sz = Y.size(), z_sz = Z.size(); + unsigned enc_count = (y_sz / 2) + (((y_sz % 2) != 0) ? 1 : 0); int dec_count = x_sz + 1; @@ -1128,10 +1088,12 @@ struct BoothPassWorker { "Result of size %d. %d encoders %d decoders\n", x_sz, y_sz, z_sz, enc_count, dec_count); - RTLIL::Wire **negi_n_int = new RTLIL::Wire *[enc_count]; - RTLIL::Wire **twoi_n_int = new RTLIL::Wire *[enc_count]; - RTLIL::Wire **onei_n_int = new RTLIL::Wire *[enc_count]; - RTLIL::Wire **cori_n_int = new RTLIL::Wire *[enc_count]; + SigSpec negi_n_int, twoi_n_int, onei_n_int, cori_n_int; + + negi_n_int.extend_u0(enc_count); + twoi_n_int.extend_u0(enc_count); + onei_n_int.extend_u0(enc_count); + cori_n_int.extend_u0(enc_count); for (unsigned encoder_ix = 1; encoder_ix <= enc_count; encoder_ix++) { std::string enc_name = "enc_" + std::to_string(encoder_ix) + "_"; @@ -1146,38 +1108,34 @@ struct BoothPassWorker { if (encoder_ix == 1) { - BuildBr4e(enc_name, mk_wireFromSigSpec(SigSpec(State::S0)), mk_wireFromSigSpec(SigSpec(Y, 0, 1)), - mk_wireFromSigSpec(SigSpec(Y, 1, 1)), - + BuildBr4e(enc_name, State::S0, Y[0], Y[1], negi_n_int[encoder_ix - 1], twoi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], cori_n_int[encoder_ix - 1]); } else { - RTLIL::Wire *y1_wire; - RTLIL::Wire *y2_wire; - RTLIL::Wire *y3_wire; + SigBit y1, y2, y3; + + y1 = Y[(encoder_ix - 1) * 2 - 1]; - y1_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2 - 1), 1)); //-1 if ((encoder_ix - 1) * 2 >= (unsigned)y_sz) - y2_wire = mk_wireFromSigSpec(SigSpec(State::S0)); // constant 0 + y2 = State::S0; // constant 0 else - y2_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2), 1)); // 0 + y2 = Y[(encoder_ix - 1) * 2]; // 0 if (((encoder_ix - 1) * 2 + 1) >= (unsigned)y_sz) - y3_wire = mk_wireFromSigSpec(SigSpec(State::S0)); // constant 0 + y3 = State::S0; // constant 0 else - y3_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2 + 1), 1)); //+1 - - BuildBr4e(enc_name, y1_wire, y2_wire, y3_wire, + y3 = Y[(encoder_ix - 1) * 2 + 1]; //+1 + BuildBr4e(enc_name, y1, y2, y3, negi_n_int[encoder_ix - 1], twoi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], cori_n_int[encoder_ix - 1]); } } // Decoders and PP generation - RTLIL::Wire **PPij = new RTLIL::Wire *[enc_count * dec_count]; - RTLIL::Wire **nxj = new RTLIL::Wire *[enc_count * dec_count]; + SigSpec PPij(State::S0, enc_count * dec_count); + SigSpec nxj(State::S0, enc_count * dec_count); for (int encoder_ix = 1; encoder_ix <= (int)enc_count; encoder_ix++) { for (int decoder_ix = 1; decoder_ix <= dec_count; decoder_ix++) { @@ -1220,16 +1178,16 @@ struct BoothPassWorker { std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; BuildBr4d(dec_name, nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1], twoi_n_int[encoder_ix - 1], - mk_wireFromSigSpec(SigSpec(X, decoder_ix - 1, 1)), negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], + X[decoder_ix - 1], negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1], nxj[((encoder_ix - 1) * dec_count) + decoder_ix]); } // duplicate end for sign fix // applies to 9th decoder (xsz+1 decoder). std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(x_sz + 1) + "_"; - RTLIL::Wire *unused_op = nullptr; + SigBit unused_op; BuildBr4d(dec_name, nxj[((encoder_ix - 1) * dec_count) + dec_count - 1], twoi_n_int[encoder_ix - 1], - mk_wireFromSigSpec(SigSpec(X, dec_count - 2, 1)), negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], + X[dec_count - 2], negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], PPij[((encoder_ix - 1) * dec_count) + dec_count - 1], unused_op); } @@ -1239,8 +1197,8 @@ struct BoothPassWorker { int fa_el_ix = 0; int fa_row_ix = 0; // use 1 d arrays (2d cannot have variable sized indices) - RTLIL::Wire **fa_sum_n = new RTLIL::Wire *[fa_row_count * fa_count]; - RTLIL::Wire **fa_carry_n = new RTLIL::Wire *[fa_row_count * fa_count]; + SigSpec fa_sum_n(State::S0, fa_row_count * fa_count); + SigSpec fa_carry_n(State::S0, fa_row_count * fa_count); for (fa_row_ix = 0; fa_row_ix < fa_row_count; fa_row_ix++) { for (fa_el_ix = 0; fa_el_ix < fa_count; fa_el_ix++) { @@ -1416,11 +1374,11 @@ struct BoothPassWorker { } // instantiate the cpa - RTLIL::Wire **cpa_carry = new RTLIL::Wire *[z_sz]; + SigSpec cpa_carry; for (int cix = 0; cix < z_sz; cix++) { std::string cpa_cix_name = "cpa_carry_" + std::to_string(cix) + "_"; - cpa_carry[cix] = module->addWire(new_id(cpa_cix_name, __LINE__, ""), 1); + cpa_carry.append(module->addWire(new_id(cpa_cix_name, __LINE__, ""), 1)); } for (int cpa_ix = 0; cpa_ix < z_sz; cpa_ix++) { @@ -1439,7 +1397,7 @@ struct BoothPassWorker { buf->setParam(ID::A_WIDTH, 1); buf->setParam(ID::Y_WIDTH, 1); buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, SigSpec(Z, cpa_ix, 1)); + buf->setPort(ID::Y, Z[cpa_ix]); cpa_ix++; buf_name = "pp_buf_" + std::to_string(cpa_ix) + "_" + "driven_by_fa_row_" + std::to_string(fa_row_ix) + "_"; @@ -1448,22 +1406,22 @@ struct BoothPassWorker { buf->setParam(ID::A_WIDTH, 1); buf->setParam(ID::Y_WIDTH, 1); buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, SigSpec(Z, cpa_ix, 1)); + buf->setPort(ID::Y, Z[cpa_ix]); } else { int offset = fa_row_count * 2; bool base_case = cpa_ix - offset == 0 ? true : false; std::string cpa_name = "cpa_" + std::to_string(cpa_ix - offset) + "_"; - RTLIL::Wire *ci_wire; + SigBit ci; if (base_case) - ci_wire = cori_n_int[enc_count - 1]; + ci = cori_n_int[enc_count - 1]; else - ci_wire = cpa_carry[cpa_ix - offset - 1]; + ci = cpa_carry[cpa_ix - offset - 1]; - RTLIL::Wire *op_wire = module->addWire(NEW_ID, 1); - BuildHa(cpa_name, fa_sum_n[(fa_row_count - 1) * fa_count + cpa_ix - offset + 2], ci_wire, op_wire, + SigBit op; + BuildHa(cpa_name, fa_sum_n[(fa_row_count - 1) * fa_count + cpa_ix - offset + 2], ci, op, cpa_carry[cpa_ix - offset]); - module->connect(op_wire, SigSpec(Z, cpa_ix, 1)); + module->connect(Z[cpa_ix], op); } } @@ -1473,35 +1431,23 @@ struct BoothPassWorker { // std::string q1_name = "icb_booth_q1_"; - RTLIL::Wire *pp0_o_int; - RTLIL::Wire *pp1_o_int; - RTLIL::Wire *nxj_o_int; - RTLIL::Wire *cor_o_int; + SigBit pp0_o_int; + SigBit pp1_o_int; + SigBit nxj_o_int; + SigBit cor_o_int; BuildBoothQ1(q1_name, negi_n_int[0], // negi cori_n_int[0], // cori - mk_wireFromSigSpec(SigSpec(X, 0, 1)), // x0 - mk_wireFromSigSpec(SigSpec(X, 1, 1)), // x1 - mk_wireFromSigSpec(SigSpec(Y, 0, 1)), // y0 - mk_wireFromSigSpec(SigSpec(Y, 1, 1)), // y1 + X[0], X[1], Y[0], Y[1], nxj_o_int, cor_o_int, pp0_o_int, pp1_o_int); - join_wires_with_buffer(pp0_o_int, fa_sum_n[(0 * fa_count) + 0]); - join_wires_with_buffer(pp1_o_int, fa_sum_n[(0 * fa_count) + 1]); - join_wires_with_buffer(cor_o_int, fa_carry_n[(0 * fa_count) + 1]); - join_wires_with_buffer(nxj_o_int, nxj[(0 * dec_count) + 2]); - - delete[] negi_n_int; - delete[] twoi_n_int; - delete[] onei_n_int; - delete[] cori_n_int; - - delete[] fa_sum_n; - delete[] fa_carry_n; - delete[] cpa_carry; + module->connect(fa_sum_n[(0 * fa_count) + 0], pp0_o_int); + module->connect(fa_sum_n[(0 * fa_count) + 1], pp1_o_int); + module->connect(fa_carry_n[(0 * fa_count) + 1], cor_o_int); + module->connect(nxj[(0 * dec_count) + 2], nxj_o_int); } }; From cb05262fc4098507e7be1fd52fe666a606687f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 19 Sep 2023 13:06:05 +0200 Subject: [PATCH 060/173] booth: Remove now-unused helpers --- passes/techmap/booth.cc | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index fe9c1cec6c0..2713d33956a 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -66,33 +66,6 @@ struct BoothPassWorker { BoothPassWorker(RTLIL::Module *module) : module(module), sigmap(module) { booth_counter = 0; } - // Helper routines for building architecture subcomponents - - RTLIL::Wire *mk_wireFromSigSpec(const SigSpec &v) - { - - auto g = module->addCell(NEW_ID, ID($pos)); - Wire *ret = module->addWire(NEW_ID, 1); - g->setPort(ID::A, v); - g->setPort(ID::Y, ret); - g->setParam(ID::A_WIDTH, 1); - g->setParam(ID::Y_WIDTH, 1); - g->setParam(ID::A_SIGNED, false); - return ret; - } - - // fuse wires. - void join_wires_with_buffer(RTLIL::Wire *ip, RTLIL::Wire *op) - { - std::string wire_name = "join_"; - auto g = module->addCell(new_id(wire_name, __LINE__, ""), ID($pos)); - g->setParam(ID::A_WIDTH, 1); - g->setParam(ID::Y_WIDTH, 1); - g->setParam(ID::A_SIGNED, false); - g->setPort(ID::A, ip); - g->setPort(ID::Y, op); - } - // Unary gate RTLIL::Wire *mk_ugate1(const RTLIL::IdString &red_typ, std::string &name, SigBit ip1, std::string &op_name) { From 986507f95fa69c7b35960750f583f49e672062d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 19 Sep 2023 15:48:23 +0200 Subject: [PATCH 061/173] booth: Streamline the low-level circuit emission For the basic single-bit operations, opt for gate cells (`$_AND_` etc.) instead of the coarse cells (`$and` etc.). For the emission of cells move to the conventional module methods (`module->addAndGate`) away from the local helpers. While at it, touch on the surrounding code. --- passes/techmap/booth.cc | 151 +++++++++++++++------------------------- 1 file changed, 58 insertions(+), 93 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index 2713d33956a..64a924e4ffb 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -108,98 +108,88 @@ struct BoothPassWorker { } // Booth unsigned decoder lsb - void BuildBur4d_lsb(std::string &name, SigBit lsb_i, SigBit one_i, SigBit s_i, SigBit &ppij_o, - std::string op_wire_name) + SigBit Bur4d_lsb(std::string name, SigBit lsb_i, SigBit one_i, SigBit s_i) { - std::string empty; - auto and_op = mk_ugate2(ID($and), name, lsb_i, one_i, empty); - ppij_o = mk_ugate2(ID($xor), name, and_op, s_i, op_wire_name); + SigBit and_op = module->AndGate(NEW_ID_SUFFIX(name), lsb_i, one_i); + return module->XorGate(NEW_ID_SUFFIX(name), and_op, s_i); } // Booth unsigned radix4 decoder - void BuildBur4d_n(std::string &name, SigBit yn_i, SigBit ynm1_i, SigBit one_i, SigBit two_i, SigBit s_i, - SigBit &ppij_o) + SigBit Bur4d_n(std::string name, SigBit yn_i, SigBit ynm1_i, SigBit one_i, SigBit two_i, SigBit s_i) { // ppij = ((yn & one) | (ynm1 & two)) ^ s; - std::string empty; - auto an1 = mk_ugate2(ID($and), name, yn_i, one_i, empty); - auto an2 = mk_ugate2(ID($and), name, ynm1_i, two_i, empty); - auto or1 = mk_ugate2(ID($or), name, an1, an2, empty); - ppij_o = mk_ugate2(ID($xor), name, s_i, or1, empty); + SigBit an1 = module->AndGate(NEW_ID_SUFFIX(name), yn_i, one_i); + SigBit an2 = module->AndGate(NEW_ID_SUFFIX(name), ynm1_i, two_i); + SigBit or1 = module->OrGate(NEW_ID_SUFFIX(name), an1, an2); + return module->XorGate(NEW_ID_SUFFIX(name), s_i, or1); } // Booth unsigned radix4 decoder - void BuildBur4d_msb(std::string &name, SigBit msb_i, SigBit two_i, SigBit s_i, SigBit &ppij_o) + SigBit Bur4d_msb(std::string name, SigBit msb_i, SigBit two_i, SigBit s_i) { // ppij = (msb & two) ^ s; - std::string empty; - auto an1 = mk_ugate2(ID($and), name, msb_i, two_i, empty); - ppij_o = mk_ugate2(ID($xor), name, s_i, an1, empty); + SigBit an1 = module->AndGate(NEW_ID_SUFFIX(name), msb_i, two_i); + return module->XorGate(NEW_ID_SUFFIX(name), s_i, an1); } // half adder, used in CPA - void BuildHa(std::string &name, SigBit a_i, SigBit b_i, SigBit &s_o, SigBit &c_o) + void BuildHa(std::string name, SigBit a_i, SigBit b_i, SigBit &s_o, SigBit &c_o) { - std::string empty; - s_o = mk_ugate2(ID($xor), name, a_i, b_i, empty); - c_o = mk_ugate2(ID($and), name, a_i, b_i, empty); + s_o = module->XorGate(NEW_ID_SUFFIX(name), a_i, b_i); + c_o = module->AndGate(NEW_ID_SUFFIX(name), a_i, b_i); } // Booth unsigned radix 4 encoder - void BuildBur4e(std::string &name, SigBit y0_i, SigBit y1_i, SigBit y2_i, + void BuildBur4e(std::string name, SigBit y0_i, SigBit y1_i, SigBit y2_i, SigBit &one_o, SigBit &two_o, SigBit &s_o, SigBit &sb_o) { - - std::string empty; - one_o = mk_ugate2(ID($xor), name, y0_i, y1_i, empty); + one_o = module->XorGate(NEW_ID_SUFFIX(name), y0_i, y1_i); s_o = y2_i; - sb_o = mk_ugate1(ID($not), name, y2_i, empty); - auto inv_y1_xor_y2 = mk_ugate1(ID($not), name, mk_ugate2(ID($xor), name, y1_i, y2_i, empty), empty); - two_o = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, inv_y1_xor_y2, one_o, empty), empty); + sb_o = module->NotGate(NEW_ID_SUFFIX(name), y2_i); + SigBit y1_xnor_y2 = module->XnorGate(NEW_ID_SUFFIX(name), y1_i, y2_i); + two_o = module->NorGate(NEW_ID_SUFFIX(name), y1_xnor_y2, one_o); } - void BuildBr4e(std::string &name, SigBit y2_m1_i, + void BuildBr4e(std::string name, SigBit y2_m1_i, SigBit y2_i, // y2i SigBit y2_p1_i, SigBit &negi_o, SigBit &twoi_n_o, SigBit &onei_n_o, SigBit &cori_o) { + auto y2_p1_n = module->NotGate(NEW_ID_SUFFIX(name), y2_p1_i); + auto y2_n = module->NotGate(NEW_ID_SUFFIX(name), y2_i); + auto y2_m1_n = module->NotGate(NEW_ID_SUFFIX(name), y2_m1_i); - std::string empty; - auto y2_p1_n = mk_ugate1(ID($not), name, y2_p1_i, empty); - auto y2_n = mk_ugate1(ID($not), name, y2_i, empty); - auto y2_m1_n = mk_ugate1(ID($not), name, y2_m1_i, empty); + negi_o = y2_p1_i; - // negi_o = y2_p1_i - negi_o = mk_ugate1(ID($pos), name, y2_p1_i, empty); // twoi_n = ~( // (y2_p1_n & y2_i & y2_m1_i) | // (y2_p1 & y2_n & y2_m1_n) // ) - auto and3_1 = mk_ugate2(ID($and), name, y2_p1_n, mk_ugate2(ID($and), name, y2_i, y2_m1_i, empty), empty); - auto and3_2 = mk_ugate2(ID($and), name, y2_p1_i, mk_ugate2(ID($and), name, y2_n, y2_m1_n, empty), empty); + twoi_n_o = module->NorGate(NEW_ID_SUFFIX(name), + module->AndGate(NEW_ID_SUFFIX(name), y2_p1_n, module->AndGate(NEW_ID_SUFFIX(name), y2_i, y2_m1_i)), + module->AndGate(NEW_ID_SUFFIX(name), y2_p1_i, module->AndGate(NEW_ID_SUFFIX(name), y2_n, y2_m1_n)) + ); - twoi_n_o = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, and3_1, and3_2, empty), empty); // onei_n = ~(y2_m1_i ^ y2_i); - onei_n_o = mk_ugate1(ID($not), name, mk_ugate2(ID($xor), name, y2_m1_i, y2_i, empty), empty); + onei_n_o = module->XnorGate(NEW_ID_SUFFIX(name), y2_m1_i, y2_i); // cori = (y2_m1_n | y2_n) & y2_p1_i; - cori_o = mk_ugate2(ID($and), name, y2_p1_i, mk_ugate2(ID($or), name, y2_m1_n, y2_n, empty), empty); + cori_o = module->AndGate(NEW_ID_SUFFIX(name), module->OrGate(NEW_ID_SUFFIX(name), y2_m1_n, y2_n), y2_p1_i); } // // signed booth radix 4 decoder // - void BuildBr4d(std::string &name, SigBit nxj_m1_i, SigBit twoi_n_i, SigBit xj_i, SigBit negi_i, SigBit onei_n_i, + void BuildBr4d(std::string name, SigBit nxj_m1_i, SigBit twoi_n_i, SigBit xj_i, SigBit negi_i, SigBit onei_n_i, SigBit &ppij_o, SigBit &nxj_o) { - - std::string empty; // nxj_in = xnor(xj,negi) // nxj_o = xnj_in, // ppij = ~( (nxj_m1_i | twoi_n_i) & (nxj_int | onei_n_i)); - nxj_o = mk_ugate2(ID($xnor), name, xj_i, negi_i, empty); - SigBit or1 = mk_ugate2(ID($or), name, nxj_m1_i, twoi_n_i, empty); - SigBit or2 = mk_ugate2(ID($or), name, nxj_o, onei_n_i, empty); - ppij_o = mk_ugate1(ID($not), name, mk_ugate2(ID($and), name, or1, or2, empty), empty); + nxj_o = module->XnorGate(NEW_ID_SUFFIX(name), xj_i, negi_i); + ppij_o = module->NandGate(NEW_ID_SUFFIX(name), + module->OrGate(NEW_ID_SUFFIX(name), nxj_m1_i, twoi_n_i), + module->OrGate(NEW_ID_SUFFIX(name), nxj_o, onei_n_i) + ); } /* @@ -207,7 +197,7 @@ struct BoothPassWorker { using non-booth encoded logic. We can save a booth encoder for the first couple of bits. */ - void BuildBoothQ1(std::string &name, SigBit negi_i, SigBit cori_i, SigBit x0_i, SigBit x1_i, SigBit y0_i, + void BuildBoothQ1(std::string name, SigBit negi_i, SigBit cori_i, SigBit x0_i, SigBit x1_i, SigBit y0_i, SigBit y1_i, SigBit &nxj_o, SigBit &cor_o, SigBit &pp0_o, SigBit &pp1_o) { @@ -222,15 +212,14 @@ struct BoothPassWorker { //correction propagation assign CORO = (~PP1 & ~PP0)? CORI : 1'b0; */ - std::string empty; - nxj_o = mk_ugate2(ID($xnor), name, x1_i, negi_i, empty); - pp0_o = mk_ugate2(ID($and), name, x0_i, y0_i, empty); - SigBit pp1_1_int = mk_ugate2(ID($and), name, x1_i, y0_i, empty); - SigBit pp1_2_int = mk_ugate2(ID($and), name, x0_i, y1_i, empty); - pp1_o = mk_ugate2(ID($xor), name, pp1_1_int, pp1_2_int, empty); - - SigBit pp1_nor_pp0 = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, pp1_o, pp0_o, empty), empty); - cor_o = mk_ugate2(ID($and), name, pp1_nor_pp0, cori_i, empty); + nxj_o = module->XnorGate(NEW_ID_SUFFIX(name), x1_i, negi_i); + pp0_o = module->AndGate(NEW_ID_SUFFIX(name), x0_i, y0_i); + SigBit pp1_1_int = module->AndGate(NEW_ID_SUFFIX(name), x1_i, y0_i); + SigBit pp1_2_int = module->AndGate(NEW_ID_SUFFIX(name), x0_i, y1_i); + pp1_o = module->XorGate(NEW_ID_SUFFIX(name), pp1_1_int, pp1_2_int); + + SigBit pp1_nor_pp0 = module->NorGate(NEW_ID_SUFFIX(name), pp1_o, pp0_o); + cor_o = module->AndGate(NEW_ID_SUFFIX(name), pp1_nor_pp0, cori_i); } void run() @@ -454,28 +443,18 @@ struct BoothPassWorker { { (void)module; int x_sz = GetSize(X); + SigBit ppij; // lsb - std::string dec_name = "row0_lsb_dec"; - - SigBit ppij; - std::string ppij_name = "ppij_0_0"; - BuildBur4d_lsb(dec_name, X[0], one_int[0], s_int[0], ppij, ppij_name); - ppij_vec.append(ppij); + ppij_vec.append(Bur4d_lsb("row0_lsb_dec", X[0], one_int[0], s_int[0])); // 1..xsize -1 - for (int i = 1; i < x_sz; i++) { - dec_name = "row0_dec_" + std::to_string(i); - SigBit ppij; - BuildBur4d_n(dec_name, X[i], X[i - 1], one_int[0], two_int[0], - s_int[0], ppij); - ppij_vec.append(ppij); - } + for (int i = 1; i < x_sz; i++) + ppij_vec.append(Bur4d_n(stringf("row0_dec_%d", i), X[i], X[i - 1], + one_int[0], two_int[0], s_int[0])); // The redundant bit. Duplicate decoding of last bit. - dec_name = "row0_dec_msb"; - BuildBur4d_msb(dec_name, X[x_sz - 1], two_int[0], s_int[0], ppij); - ppij_vec.append(ppij); + ppij_vec.append(Bur4d_msb("row0_dec_msb", X[x_sz - 1], two_int[0], s_int[0])); // append the sign bits ppij_vec.append(s_int[0]); @@ -494,37 +473,23 @@ struct BoothPassWorker { int x_sz = GetSize(X); // lsb - std::string ppij_name = "ppij_" + std::to_string(row_ix) + "_0"; - SigBit ppij; - std::string empty; - std::string dec_name = "row" + std::to_string(row_ix) + "_lsb_dec"; - BuildBur4d_lsb(dec_name, X[0], one_int, s_int, ppij, empty); - - ppij_vec.append(ppij); + ppij_vec.append(Bur4d_lsb(stringf("row_%d_lsb_dec", row_ix), X[0], one_int, s_int)); // core bits - for (int i = 1; i < x_sz; i++) { - - dec_name = "row_" + std::to_string(row_ix) + "_dec_" + std::to_string(i); - BuildBur4d_n(dec_name, X[i], X[i - 1], - one_int, two_int, s_int, ppij); - ppij_vec.append(ppij); - } + for (int i = 1; i < x_sz; i++) + ppij_vec.append(Bur4d_n(stringf("row_%d_dec_%d", row_ix, i), X[i], X[i - 1], + one_int, two_int, s_int)); // redundant bit - - dec_name = "row_dec_red"; - BuildBur4d_msb(dec_name, X[x_sz - 1], two_int, s_int, ppij); - ppij_vec.append(ppij); + ppij_vec.append(Bur4d_msb("row_dec_red", X[x_sz - 1], two_int, s_int)); // sign bit - if (no_sign == false) // if no sign is false then make a sign bit + if (!no_sign) // if no sign is false then make a sign bit ppij_vec.append(sb_int); // constant bit - if (no_constant == false) { // if non constant is false make a constant bit + if (!no_constant) // if non constant is false make a constant bit ppij_vec.append(State::S1); - } } void DebugDumpAlignPP(std::vector> &aligned_pp) From 30f8387b75f205ff360292bcd2459191daed9a66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 19 Sep 2023 16:25:10 +0200 Subject: [PATCH 062/173] booth: Rewrite the main cell selection loop --- passes/techmap/booth.cc | 180 ++++++++++++++++++---------------------- 1 file changed, 82 insertions(+), 98 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index 64a924e4ffb..df0f82ec289 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -225,108 +225,92 @@ struct BoothPassWorker { void run() { for (auto cell : module->selected_cells()) { - if (cell->type.in(ID($mul))) { - RTLIL::SigSpec A = sigmap(cell->getPort(ID::A)); - RTLIL::SigSpec B = sigmap(cell->getPort(ID::B)); - RTLIL::SigSpec Y = sigmap(cell->getPort(ID::Y)); - if (GetSize(A) >= 4 && GetSize(B) >= 4 && GetSize(Y) >= 8 && - ((cell->getParam(ID::A_SIGNED).as_bool() && cell->getParam(ID::B_SIGNED).as_bool()) || - (!cell->getParam(ID::A_SIGNED).as_bool() && !cell->getParam(ID::B_SIGNED).as_bool()))) { - bool is_signed = false; - if (cell->getParam(ID::A_SIGNED).as_bool()) { - log(" By passing macc inferencing for signed multiplier -- generating booth\n"); - is_signed = true; - } else - log(" By passing macc inferencing for unsigned multiplier -- generating booth\n"); - - int x_sz = GetSize(A); - int y_sz = GetSize(B); - int z_sz = GetSize(Y); - - // To simplify the generator size the arguments - // to be the same. Then allow logic synthesis to - // clean things up. Size to biggest - - int x_sz_revised = x_sz; - int y_sz_revised = y_sz; - - if (x_sz != y_sz) { - if (x_sz < y_sz) { - if (y_sz % 2 != 0) { - x_sz_revised = y_sz + 1; - y_sz_revised = y_sz + 1; - } else - x_sz_revised = y_sz; - - } else { - if (x_sz % 2 != 0) { - y_sz_revised = x_sz + 1; - x_sz_revised = x_sz + 1; - } else - y_sz_revised = x_sz; - } + if (cell->type != ID($mul)) + continue; + + SigSpec A = cell->getPort(ID::A); + SigSpec B = cell->getPort(ID::B); + SigSpec Y = cell->getPort(ID::Y); + int x_sz = GetSize(A), y_sz = GetSize(B), z_sz = GetSize(Y); + + if (x_sz < 4 || y_sz < 4 || z_sz < 8) { + log_debug("Not mapping cell %s sized at %dx%x, %x: size below threshold\n", + log_id(cell), x_sz, y_sz, z_sz); + continue; + } + + log_assert(cell->getParam(ID::A_SIGNED).as_bool() == cell->getParam(ID::B_SIGNED).as_bool()); + bool is_signed = cell->getParam(ID::A_SIGNED).as_bool(); + + log("Mapping cell %s to %s Booth multiplier\n", log_id(cell), is_signed ? "signed" : "unsigned"); + + // To simplify the generator size the arguments + // to be the same. Then allow logic synthesis to + // clean things up. Size to biggest + + int x_sz_revised = x_sz; + int y_sz_revised = y_sz; + + if (x_sz != y_sz) { + if (x_sz < y_sz) { + if (y_sz % 2 != 0) { + x_sz_revised = y_sz + 1; + y_sz_revised = y_sz + 1; + } else { + x_sz_revised = y_sz; + } + } else { + if (x_sz % 2 != 0) { + y_sz_revised = x_sz + 1; + x_sz_revised = x_sz + 1; } else { - if (x_sz % 2 != 0) { - y_sz_revised = y_sz + 1; - x_sz_revised = x_sz + 1; - } + y_sz_revised = x_sz; } - - log_assert((x_sz_revised == y_sz_revised) && (x_sz_revised % 2 == 0) && (y_sz_revised % 2 == 0)); - - Wire *expanded_A = module->addWire(NEW_ID, x_sz_revised); - Wire *expanded_B = module->addWire(NEW_ID, y_sz_revised); - - std::string buf_name = "expand_a_buf_"; - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setParam(ID::A_WIDTH, x_sz); - buf->setParam(ID::Y_WIDTH, x_sz_revised); - buf->setPort(ID::A, SigSpec(A)); - buf->setParam(ID::A_SIGNED, is_signed ? true : false); - buf->setPort(ID::Y, SigSpec(expanded_A)); - - buf_name = "expand_b_buf_"; - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, SigSpec(B)); - buf->setParam(ID::A_WIDTH, y_sz); - buf->setParam(ID::Y_WIDTH, y_sz_revised); - buf->setParam(ID::A_SIGNED, is_signed ? true : false); - buf->setPort(ID::Y, SigSpec(expanded_B)); - - // Make sure output domain is big enough to take - // all combinations. - // Later logic synthesis will kill unused - // portions of the output domain. - - unsigned required_op_size = x_sz_revised + y_sz_revised; - Wire *expanded_Y = module->addWire(NEW_ID, required_op_size); - // now connect the expanded_Y with a tap to fill out sig Spec Y - buf_name = "reducer_buf_"; - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, expanded_Y); - buf->setParam(ID::A_WIDTH, required_op_size); - buf->setParam(ID::Y_WIDTH, z_sz); // The real user width - buf->setParam(ID::A_SIGNED, is_signed ? true : false); - // wire in output Y - buf->setPort(ID::Y, SigSpec(Y)); - - if (is_signed == false) /* unsigned multiplier */ - CreateBoothUMult(module, - expanded_A, // multiplicand - expanded_B, // multiplier(scanned) - expanded_Y // result - ); - else /*signed multiplier */ - CreateBoothSMult(module, - expanded_A, // multiplicand - expanded_B, // multiplier(scanned) - expanded_Y // result (sized) - ); - module->remove(cell); - booth_counter++; - continue; } + } else { + if (x_sz % 2 != 0) { + y_sz_revised = y_sz + 1; + x_sz_revised = x_sz + 1; + } + } + + log_assert((x_sz_revised == y_sz_revised) && (x_sz_revised % 2 == 0) && (y_sz_revised % 2 == 0)); + + + A.extend_u0(x_sz_revised, is_signed); + B.extend_u0(y_sz_revised, is_signed); + + // Make sure output domain is big enough to take + // all combinations. + // Later logic synthesis will kill unused + // portions of the output domain. + + int required_op_size = x_sz_revised + y_sz_revised; + + if (required_op_size != z_sz) { + SigSpec expanded_Y = module->addWire(NEW_ID, required_op_size); + SigSpec Y_driver = expanded_Y; + Y_driver.extend_u0(Y.size(), is_signed); + module->connect(Y, Y_driver); + Y = expanded_Y; } + log_assert(GetSize(Y) == required_op_size); + + if (!is_signed) /* unsigned multiplier */ + CreateBoothUMult(module, + A, // multiplicand + B, // multiplier(scanned) + Y // result + ); + else /* signed multiplier */ + CreateBoothSMult(module, + A, // multiplicand + B, // multiplier(scanned) + Y // result (sized) + ); + + module->remove(cell); + booth_counter++; } } From 62302f601ddc9810b5b780748b97c84d875dfa10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 19 Sep 2023 16:25:40 +0200 Subject: [PATCH 063/173] booth: Remove more of unused helpers --- passes/techmap/booth.cc | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index df0f82ec289..086b2e85b8e 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -66,47 +66,6 @@ struct BoothPassWorker { BoothPassWorker(RTLIL::Module *module) : module(module), sigmap(module) { booth_counter = 0; } - // Unary gate - RTLIL::Wire *mk_ugate1(const RTLIL::IdString &red_typ, std::string &name, SigBit ip1, std::string &op_name) - { - std::string op_wire_name; - if (op_name.empty()) - op_wire_name = name + "_o"; - else - op_wire_name = op_name; - RTLIL::Wire *ret = module->addWire(new_id(op_wire_name, __LINE__, ""), 1); - auto g = module->addCell(new_id(name, __LINE__, ""), red_typ); - g->setPort(ID::A, ip1); - g->setPort(ID::Y, ret); - g->setParam(ID::A_SIGNED, false); - g->setParam(ID::A_WIDTH, 1); - g->setParam(ID::Y_WIDTH, 1); - return ret; - } - - // Binary gate - RTLIL::Wire *mk_ugate2(const RTLIL::IdString &red_typ, std::string &name, SigBit ip1, SigBit ip2, std::string &op_name) - { - auto g = module->addCell(new_id(name, __LINE__, ""), red_typ); - std::string op_wire_name; - if (op_name.empty()) - op_wire_name = name + "_o"; - else - op_wire_name = op_name; - - auto ret = module->addWire(new_id(op_wire_name, __LINE__, ""), 1); - - g->setPort(ID::A, ip1); - g->setPort(ID::B, ip2); - g->setPort(ID::Y, ret); - g->setParam(ID::A_SIGNED, false); - g->setParam(ID::B_SIGNED, false); - g->setParam(ID::A_WIDTH, 1); - g->setParam(ID::B_WIDTH, 1); - g->setParam(ID::Y_WIDTH, 1); - return ret; - } - // Booth unsigned decoder lsb SigBit Bur4d_lsb(std::string name, SigBit lsb_i, SigBit one_i, SigBit s_i) { From d641dfaec2a67a25afb4a82469af3b0627e9b334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 19 Sep 2023 16:33:22 +0200 Subject: [PATCH 064/173] rtlil: Add helper to emit full-adder cells --- kernel/rtlil.cc | 13 +++++++++++++ kernel/rtlil.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 1b57af60acb..efd76e9cd25 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -2677,6 +2677,19 @@ RTLIL::Cell* RTLIL::Module::addPow(RTLIL::IdString name, const RTLIL::SigSpec &s return cell; } +RTLIL::Cell* RTLIL::Module::addFa(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_x, const RTLIL::SigSpec &sig_y, const std::string &src) +{ + RTLIL::Cell *cell = addCell(name, ID($fa)); + cell->parameters[ID::WIDTH] = sig_a.size(); + cell->setPort(ID::A, sig_a); + cell->setPort(ID::B, sig_b); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::X, sig_x); + cell->setPort(ID::Y, sig_y); + cell->set_src_attribute(src); + return cell; +} + RTLIL::Cell* RTLIL::Module::addSlice(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const offset, const std::string &src) { RTLIL::Cell *cell = addCell(name, ID($slice)); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index c50d75e9087..3dff48b4f79 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1298,6 +1298,8 @@ struct RTLIL::Module : public RTLIL::AttrObject RTLIL::Cell* addModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addPow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool a_signed = false, bool b_signed = false, const std::string &src = ""); + RTLIL::Cell* addFa (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_x, const RTLIL::SigSpec &sig_y, const std::string &src = ""); + RTLIL::Cell* addLogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addLogicAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addLogicOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); From cde2a0b926c1edd24936748e878eee40a3389f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 25 Sep 2023 13:54:24 +0200 Subject: [PATCH 065/173] booth: Make more use of appropriate helpers Use the `addFa` helper, do not misuse `new_id` and make other changes to the transformation code. --- passes/techmap/booth.cc | 412 +++++++++++++++------------------------- 1 file changed, 152 insertions(+), 260 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index 086b2e85b8e..aa5684b7427 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -687,20 +687,15 @@ struct BoothPassWorker { // End Case else if (n == s_vec.size() - 1) { // Make the carry results.. Two extra bits after fa. - std::string fa_name = "cpa_" + std::to_string(cpa_id) + "_fa_" + std::to_string(n); - - auto fa_cell = module->addCell(new_id(fa_name, __LINE__, ""), ID($fa)); - fa_cell->setParam(ID::WIDTH, 1); - carry_name = "cpa_" + std::to_string(cpa_id) + "carry_" + std::to_string(n); - fa_cell->setPort(ID::A, s_vec[n]); - fa_cell->setPort(ID::B, c_vec[n - 1]); - fa_cell->setPort(ID::C, carry); - // wire in result and carry out - fa_cell->setPort(ID::Y, result[n]); - - // make a new carry bit for carry out... - carry = module->addWire(new_id(carry_name, __LINE__, ""), 1); - fa_cell->setPort(ID::X, carry); + SigBit carry_out = module->addWire(NEW_ID, 1); + module->addFa(NEW_ID_SUFFIX(stringf("cpa_%d_fa_%d", cpa_id, n)), + /* A */ s_vec[n], + /* B */ c_vec[n - 1], + /* C */ carry, + /* X */ carry_out, + /* Y */ result[n] + ); + carry = carry_out; #ifdef DEBUG_CPA printf("CPA bit [%d] Cell %s IPs [%s] [%s] [%s]\n", n, fa_cell->name.c_str(), s_vec[n]->name.c_str(), @@ -720,20 +715,15 @@ struct BoothPassWorker { } // Step case else { - std::string fa_name = "cpa_" + std::to_string(cpa_id) + "_fa_" + std::to_string(n); - auto fa_cell = module->addCell(new_id(fa_name, __LINE__, ""), ID($fa)); - fa_cell->setParam(ID::WIDTH, 1); - - carry_name = "cpa_" + std::to_string(cpa_id) + "carry_" + std::to_string(n); - fa_cell->setPort(ID::A, s_vec[n]); - fa_cell->setPort(ID::B, c_vec[n - 1]); - fa_cell->setPort(ID::C, carry); - // wire in result and carry out - fa_cell->setPort(ID::Y, result[n]); - // make a new carry bit for carry out... - carry = module->addWire(new_id(carry_name, __LINE__, ""), 1); - fa_cell->setPort(ID::X, carry); - + SigBit carry_out = module->addWire(NEW_ID_SUFFIX(stringf("cpa_%d_carry_%d", cpa_id, n)), 1); + module->addFa(NEW_ID_SUFFIX(stringf("cpa_%d_fa_%d", cpa_id, n)), + /* A */ s_vec[n], + /* B */ c_vec[n - 1], + /* C */ carry, + /* X */ carry_out, + /* Y */ result[n] + ); + carry = carry_out; #ifdef DEBUG_CPA printf("CPA bit [%d] Cell %s IPs [%s] [%s] [%s]\n", n, fa_cell->name.c_str(), s_vec[n]->name.c_str(), c_vec[n - 1]->name.c_str(), carry->name.c_str()); @@ -752,9 +742,6 @@ struct BoothPassWorker { int csa_ix = 0; int column_size = column_bits.size(); - static int unique_id = 0; - - unique_id++; if (column_size > 0) { int var_ix = 0; @@ -767,38 +754,23 @@ struct BoothPassWorker { if (first_csa_ips.size() > 0) { // build the first csa - std::string csa_name = - "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_" + std::to_string(unique_id) + "_"; - auto csa = module->addCell(NEW_ID, - // new_id(csa_name, - // __LINE__, - // ""), - ID($fa)); - csa->setParam(ID::WIDTH, 1); - debug_csa_trees[column_ix].push_back(csa); - csa_ix++; - - csa->setPort(ID::A, first_csa_ips[0]); - - if (first_csa_ips.size() > 1) - csa->setPort(ID::B, first_csa_ips[1]); - else - csa->setPort(ID::B, State::S0); - - if (first_csa_ips.size() > 2) - csa->setPort(ID::C, first_csa_ips[2]); - else - csa->setPort(ID::C, State::S0); + auto s_wire = module->addWire(NEW_ID_SUFFIX(stringf("csa_%d_%d_s", column_ix, csa_ix + 1)), 1); + auto c_wire = module->addWire(NEW_ID_SUFFIX(stringf("csa_%d_%d_c", column_ix, csa_ix + 1)), 1); + + auto csa = module->addFa(NEW_ID_SUFFIX(stringf("csa_%d_%d", column_ix, csa_ix)), + /* A */ first_csa_ips[0], + /* B */ first_csa_ips.size() > 1 ? first_csa_ips[1] : State::S0, + /* C */ first_csa_ips.size() > 2 ? first_csa_ips[2] : State::S0, + /* X */ c_wire, + /* Y */ s_wire + ); - std::string sum_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_s"; - auto s_wire = module->addWire(new_id(sum_wire_name, __LINE__, ""), 1); - csa->setPort(ID::Y, s_wire); s_result = s_wire; - std::string carry_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_c"; - auto c_wire = module->addWire(new_id(carry_wire_name, __LINE__, ""), 1); - csa->setPort(ID::X, c_wire); c_result = c_wire; + debug_csa_trees[column_ix].push_back(csa); + csa_ix++; + if (var_ix <= column_bits.size() - 1) carry_bits_to_sum.append(c_wire); @@ -814,32 +786,23 @@ struct BoothPassWorker { } if (csa_ips.size() > 0) { - csa_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix); - auto csa = module->addCell(new_id(csa_name, __LINE__, ""), ID($fa)); - csa->setParam(ID::WIDTH, 1); - debug_csa_trees[column_ix].push_back(csa); + auto c_wire = module->addWire(NEW_ID_SUFFIX(stringf("csa_%d_%d_c", column_ix, csa_ix + 1)), 1); + auto s_wire = module->addWire(NEW_ID_SUFFIX(stringf("csa_%d_%d_s", column_ix, csa_ix + 1)), 1); - csa_ix++; - // prior level - csa->setPort(ID::A, s_wire); - csa->setPort(ID::B, csa_ips[0]); - if (csa_ips.size() > 1) - csa->setPort(ID::C, csa_ips[1]); - else - csa->setPort(ID::C, State::S0); + auto csa = module->addFa(NEW_ID_SUFFIX(stringf("csa_%d_%d", column_ix, csa_ix)), + /* A */ s_result, + /* B */ csa_ips[0], + /* C */ csa_ips.size() > 1 ? csa_ips[1] : State::S0, + /* X */ c_wire, + /* Y */ s_wire + ); - carry_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_c"; - c_wire = module->addWire(new_id(carry_wire_name, __LINE__, ""), 1); + debug_csa_trees[column_ix].push_back(csa); + csa_ix++; if (var_ix <= column_bits.size() - 1) carry_bits_to_sum.append(c_wire); - sum_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_s"; - s_wire = module->addWire(new_id(sum_wire_name, __LINE__, ""), 1); - - csa->setPort(ID::X, c_wire); - csa->setPort(ID::Y, s_wire); - s_result = s_wire; c_result = c_wire; } @@ -854,22 +817,14 @@ struct BoothPassWorker { int y_sz = GetSize(Y); for (int y_ix = 0; y_ix < y_sz;) { - std::string enc_name = "bur_enc_" + std::to_string(encoder_ix) + "_"; - - std::string two_name = "two_int" + std::to_string(encoder_ix); - two_int.append(module->addWire(new_id(two_name, __LINE__, ""), 1)); + std::string enc_name = stringf("bur_enc_%d", encoder_ix); - std::string one_name = "one_int" + std::to_string(encoder_ix); - one_int.append(module->addWire(new_id(one_name, __LINE__, ""), 1)); - - std::string s_name = "s_int" + std::to_string(encoder_ix); - s_int.append(module->addWire(new_id(s_name, __LINE__, ""), 1)); - - std::string sb_name = "sb_int" + std::to_string(encoder_ix); - sb_int.append(module->addWire(new_id(sb_name, __LINE__, ""), 1)); + two_int.append(module->addWire(NEW_ID_SUFFIX(stringf("two_int_%d", encoder_ix)), 1)); + one_int.append(module->addWire(NEW_ID_SUFFIX(stringf("one_int_%d", encoder_ix)), 1)); + s_int.append(module->addWire(NEW_ID_SUFFIX(stringf("s_int_%d", encoder_ix)), 1)); + sb_int.append(module->addWire(NEW_ID_SUFFIX(stringf("sb_int_%d", encoder_ix)), 1)); if (y_ix == 0) { - BuildBur4e(enc_name, State::S0, Y[y_ix], Y[y_ix + 1], one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], sb_int[encoder_ix]); @@ -919,23 +874,15 @@ struct BoothPassWorker { encoder_ix++; if (need_padded_cell == true) { - // make extra encoder cell // y_ix at y0, rest 0 - std::string enc_name = "br_enc_pad" + std::to_string(encoder_ix) + "_"; - - std::string two_name = "two_int" + std::to_string(encoder_ix); - two_int.append(module->addWire(new_id(two_name, __LINE__, ""), 1)); - - std::string one_name = "one_int" + std::to_string(encoder_ix); - one_int.append(module->addWire(new_id(two_name, __LINE__, ""), 1)); + std::string enc_name = stringf("br_enc_pad_%d", encoder_ix); - std::string s_name = "s_int" + std::to_string(encoder_ix); - s_int.append(module->addWire(new_id(s_name, __LINE__, ""), 1)); - - std::string sb_name = "sb_int" + std::to_string(encoder_ix); - sb_int.append(module->addWire(new_id(sb_name, __LINE__, ""), 1)); + two_int.append(module->addWire(NEW_ID_SUFFIX(stringf("two_int_%d", encoder_ix)), 1)); + one_int.append(module->addWire(NEW_ID_SUFFIX(stringf("one_int_%d", encoder_ix)), 1)); + s_int.append(module->addWire(NEW_ID_SUFFIX(stringf("s_int_%d", encoder_ix)), 1)); + sb_int.append(module->addWire(NEW_ID_SUFFIX(stringf("sb_int_%d", encoder_ix)), 1)); SigBit one_o_int, two_o_int, s_o_int, sb_o_int; BuildBur4e(enc_name, Y[y_ix], State::S0, @@ -977,18 +924,13 @@ struct BoothPassWorker { cori_n_int.extend_u0(enc_count); for (unsigned encoder_ix = 1; encoder_ix <= enc_count; encoder_ix++) { - std::string enc_name = "enc_" + std::to_string(encoder_ix) + "_"; - std::string negi_name = "negi_n_int" + std::to_string(encoder_ix) + "_"; - negi_n_int[encoder_ix - 1] = module->addWire(new_id(negi_name, __LINE__, ""), 1); - std::string twoi_name = "twoi_n_int_" + std::to_string(encoder_ix) + "_"; - twoi_n_int[encoder_ix - 1] = module->addWire(new_id(twoi_name, __LINE__, ""), 1); - std::string onei_name = "onei_n_int_" + std::to_string(encoder_ix) + "_"; - onei_n_int[encoder_ix - 1] = module->addWire(new_id(onei_name, __LINE__, ""), 1); - std::string cori_name = "cori_n_int_" + std::to_string(encoder_ix) + "_"; - cori_n_int[encoder_ix - 1] = module->addWire(new_id(cori_name, __LINE__, ""), 1); + std::string enc_name = stringf("enc_%d", encoder_ix); + negi_n_int[encoder_ix - 1] = module->addWire(NEW_ID_SUFFIX(stringf("negi_n_int_%d", encoder_ix)), 1); + twoi_n_int[encoder_ix - 1] = module->addWire(NEW_ID_SUFFIX(stringf("twoi_n_int_%d", encoder_ix)), 1); + onei_n_int[encoder_ix - 1] = module->addWire(NEW_ID_SUFFIX(stringf("onei_n_int_%d", encoder_ix)), 1); + cori_n_int[encoder_ix - 1] = module->addWire(NEW_ID_SUFFIX(stringf("cori_n_int_%d", encoder_ix)), 1); if (encoder_ix == 1) { - BuildBr4e(enc_name, State::S0, Y[0], Y[1], negi_n_int[encoder_ix - 1], twoi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], cori_n_int[encoder_ix - 1]); @@ -1020,22 +962,18 @@ struct BoothPassWorker { for (int encoder_ix = 1; encoder_ix <= (int)enc_count; encoder_ix++) { for (int decoder_ix = 1; decoder_ix <= dec_count; decoder_ix++) { - std::string ppij_name = "ppij_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; - PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = module->addWire(new_id(ppij_name, __LINE__, ""), 1); - std::string nxj_name; - if (decoder_ix == 1) - nxj_name = "nxj_pre_dec" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; - else - nxj_name = "nxj_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; + PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = + module->addWire(NEW_ID_SUFFIX(stringf("ppij_%d_%d", encoder_ix, decoder_ix)), 1); - nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = module->addWire(new_id(nxj_name, __LINE__, ""), 1); + nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = + module->addWire(NEW_ID_SUFFIX(stringf("nxj_%s%d_%d", decoder_ix == 1 ? "pre_dec_" : "", + encoder_ix, decoder_ix)), 1); } } // // build decoder array // - for (int encoder_ix = 1; encoder_ix <= (int)enc_count; encoder_ix++) { // pre-decoder std::string pre_dec_name = "pre_dec_" + std::to_string(encoder_ix) + "_"; @@ -1043,10 +981,10 @@ struct BoothPassWorker { if (encoder_ix == 1) { // quadrant 1 optimization } else { - auto cell = module->addCell(new_id(pre_dec_name, __LINE__, ""), ID($_NOT_)); - cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - cell->setPort(ID::A, negi_n_int[encoder_ix - 1]); - cell->setPort(ID::Y, nxj[(encoder_ix - 1) * dec_count]); + module->addNotGate(NEW_ID_SUFFIX(stringf("pre_dec_%d", encoder_ix)), + negi_n_int[encoder_ix - 1], + nxj[(encoder_ix - 1) * dec_count] + ); } for (int decoder_ix = 1; decoder_ix < dec_count; decoder_ix++) { @@ -1056,8 +994,7 @@ struct BoothPassWorker { if ((decoder_ix == 1 || decoder_ix == 2) && encoder_ix == 1) continue; - std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; - + std::string dec_name = stringf("dec_%d_%d", encoder_ix, decoder_ix); BuildBr4d(dec_name, nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1], twoi_n_int[encoder_ix - 1], X[decoder_ix - 1], negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1], nxj[((encoder_ix - 1) * dec_count) + decoder_ix]); @@ -1065,7 +1002,7 @@ struct BoothPassWorker { // duplicate end for sign fix // applies to 9th decoder (xsz+1 decoder). - std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(x_sz + 1) + "_"; + std::string dec_name = stringf("dec_%d_%d", encoder_ix, x_sz + 1); SigBit unused_op; BuildBr4d(dec_name, nxj[((encoder_ix - 1) * dec_count) + dec_count - 1], twoi_n_int[encoder_ix - 1], X[dec_count - 2], negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], @@ -1083,11 +1020,10 @@ struct BoothPassWorker { for (fa_row_ix = 0; fa_row_ix < fa_row_count; fa_row_ix++) { for (fa_el_ix = 0; fa_el_ix < fa_count; fa_el_ix++) { - - std::string fa_sum_name = "fa_sum_n_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_"; - fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] = module->addWire(new_id(fa_sum_name, __LINE__, ""), 1); - std::string fa_carry_name = "fa_carry_n" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_"; - fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix] = module->addWire(new_id(fa_carry_name, __LINE__, ""), 1); + fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] = + module->addWire(NEW_ID_SUFFIX(stringf("fa_sum_n_%d_%d", fa_row_ix, fa_el_ix)), 1); + fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix] = + module->addWire(NEW_ID_SUFFIX(stringf("fa_carry_n_%d_%d", fa_row_ix, fa_el_ix)), 1); } } @@ -1110,67 +1046,52 @@ struct BoothPassWorker { // step case else if (fa_el_ix >= 2 && fa_el_ix <= x_sz) { // middle (2...x_sz cells) - bfa_name = "bfa_0_step_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - auto cell = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell->setParam(ID::WIDTH, 1); - cell->setPort(ID::A, PPij[(0 * dec_count) + fa_el_ix]); - cell->setPort(ID::B, PPij[(1 * dec_count) + fa_el_ix - 2]); - cell->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_0_step_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ PPij[(0 * dec_count) + fa_el_ix], + /* B */ PPij[(1 * dec_count) + fa_el_ix - 2], + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); } // end 3 cells: x_sz+1.2.3 // else { // fa_el_ix = x_sz+1 - bfa_name = "bfa_0_se_0" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell1->setParam(ID::WIDTH, 1); - cell1->setPort(ID::A, PPij[(0 * dec_count) + x_sz]); - cell1->setPort(ID::B, PPij[(1 * dec_count) + fa_el_ix - 2]); - cell1->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_0_se_0_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ PPij[(0 * dec_count) + x_sz], + /* B */ PPij[(1 * dec_count) + fa_el_ix - 2], + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); // exception:invert ppi fa_el_ix++; - exc_inv_name = "bfa_0_exc_inv1_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - auto cellinv1 = module->addCell(new_id(exc_inv_name, __LINE__, ""), ID($_NOT_)); - cellinv1->add_strpool_attribute(ID::src, cellinv1->get_strpool_attribute(ID::src)); - - RTLIL::Wire *d08_inv = module->addWire(NEW_ID, 1); - - cellinv1->setPort(ID::A, PPij[(0 * dec_count) + dec_count - 1]); - cellinv1->setPort(ID::Y, d08_inv); - - exc_inv_name = "bfa_0_exc_inv2_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - - auto cellinv2 = module->addCell(new_id(exc_inv_name, __LINE__, ""), ID($_NOT_)); - cellinv2->add_strpool_attribute(ID::src, cellinv2->get_strpool_attribute(ID::src)); - RTLIL::Wire *d18_inv = module->addWire(NEW_ID, 1); - cellinv2->setPort(ID::A, PPij[(1 * dec_count) + dec_count - 1]); - cellinv2->setPort(ID::Y, d18_inv); + SigBit d08_inv = module->NotGate(NEW_ID_SUFFIX(stringf("bfa_0_exc_inv1_%d_%d_L", fa_row_ix, fa_el_ix)), + PPij[(0 * dec_count) + dec_count - 1]); - bfa_name = "bfa_0_se_1_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; + SigBit d18_inv = module->NotGate(NEW_ID_SUFFIX(stringf("bfa_0_exc_inv2_%d_%d_L", fa_row_ix, fa_el_ix)), + PPij[(1 * dec_count) + dec_count - 1]); - auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell2->setParam(ID::WIDTH, 1); - cell2->setPort(ID::A, d08_inv); - cell2->setPort(ID::B, d18_inv); - cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_0_se_1_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ d08_inv, + /* B */ d18_inv, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); // sign extension fa_el_ix++; - bfa_name = "bfa_0_se_2_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - auto cell3 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell3->setParam(ID::WIDTH, 1); - cell3->setPort(ID::A, State::S0); - cell3->setPort(ID::B, State::S1); - cell3->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell3->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell3->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + + module->addFa(NEW_ID_SUFFIX(stringf("bfa_0_se_2_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ State::S0, + /* B */ State::S1, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); } } @@ -1181,74 +1102,59 @@ struct BoothPassWorker { if (fa_el_ix == 0) { // first two cells: have B input hooked to 0. // column is offset by row_ix*2 - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_base_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell1->setParam(ID::WIDTH, 1); - cell1->setPort(ID::A, fa_sum_n[(fa_row_ix - 1) * fa_count + 2]); // from prior full adder row - cell1->setPort(ID::B, State::S0); - cell1->setPort(ID::C, cori_n_int[fa_row_ix]); - cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + + module->addFa(NEW_ID_SUFFIX(stringf("bfa_base_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ fa_sum_n[(fa_row_ix - 1) * fa_count + 2], + /* B */ State::S0, + /* C */ cori_n_int[fa_row_ix], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); fa_el_ix++; - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_base_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell2->setParam(ID::WIDTH, 1); - cell2->setPort(ID::A, - fa_sum_n[(fa_row_ix - 1) * fa_count + 3]); // from prior full adder row - cell2->setPort(ID::B, State::S0); - cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_base_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ fa_sum_n[(fa_row_ix - 1) * fa_count + 3], // from prior full adder row + /* B */ State::S0, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); + } else if (fa_el_ix >= 2 && fa_el_ix <= x_sz + 1) { // middle (2...x_sz+1 cells) - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_step_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell->setParam(ID::WIDTH, 1); - cell->setPort(ID::A, fa_sum_n[(fa_row_ix - 1) * fa_count + fa_el_ix + 2]); - cell->setPort(ID::B, PPij[(fa_row_ix + 1) * dec_count + fa_el_ix - 2]); - cell->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_step_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ fa_sum_n[(fa_row_ix - 1) * fa_count + fa_el_ix + 2], + /* B */ PPij[(fa_row_ix + 1) * dec_count + fa_el_ix - 2], + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); } else if (fa_el_ix > x_sz + 1) { // end two bits: sign extension - std::string se_inv_name; - se_inv_name = "bfa_" + std::to_string(fa_row_ix) + "_se_inv_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cellinv = module->addCell(new_id(se_inv_name, __LINE__, ""), ID($_NOT_)); - cellinv->add_strpool_attribute(ID::src, cellinv->get_strpool_attribute(ID::src)); - RTLIL::Wire *d_inv = module->addWire(NEW_ID, 1); - cellinv->setPort(ID::A, PPij[((fa_row_ix + 1) * dec_count) + dec_count - 1]); - cellinv->setPort(ID::Y, d_inv); - - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_se_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell1->setParam(ID::WIDTH, 1); - cell1->setPort(ID::A, fa_carry_n[((fa_row_ix - 1) * fa_count) + fa_count - 1]); - cell1->setPort(ID::B, d_inv); - cell1->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + SigBit d_inv = module->NotGate(NEW_ID_SUFFIX(stringf("bfa_se_inv_%d_%d_L", fa_row_ix, fa_el_ix)), + PPij[((fa_row_ix + 1) * dec_count) + dec_count - 1]); + + module->addFa(NEW_ID_SUFFIX(stringf("bfa_se_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ fa_carry_n[((fa_row_ix - 1) * fa_count) + fa_count - 1], + /* B */ d_inv, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); fa_el_ix++; // sign extension - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_se_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell2->setParam(ID::WIDTH, 1); - cell2->setPort(ID::A, State::S0); - cell2->setPort(ID::B, State::S1); - cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_se_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ State::S0, + /* B */ State::S1, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); } } } @@ -1257,13 +1163,10 @@ struct BoothPassWorker { // instantiate the cpa SigSpec cpa_carry; - for (int cix = 0; cix < z_sz; cix++) { - std::string cpa_cix_name = "cpa_carry_" + std::to_string(cix) + "_"; - cpa_carry.append(module->addWire(new_id(cpa_cix_name, __LINE__, ""), 1)); - } + for (int cix = 0; cix < z_sz; cix++) + cpa_carry.append(module->addWire(NEW_ID_SUFFIX(stringf("cpa_carry_%d", cix)), 1)); for (int cpa_ix = 0; cpa_ix < z_sz; cpa_ix++) { - // The end case where we pass the last two summands // from prior row directly to product output // without using a cpa cell. This is always @@ -1271,27 +1174,16 @@ struct BoothPassWorker { if (cpa_ix <= fa_row_count * 2 - 1) { int fa_row_ix = cpa_ix / 2; - std::string buf_name = - "pp_buf_" + std::to_string(cpa_ix) + "_" + "driven_by_fa_row_" + std::to_string(fa_row_ix) + "_"; - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, fa_sum_n[(fa_row_ix * fa_count) + 0]); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, Z[cpa_ix]); + module->addBufGate(NEW_ID_SUFFIX(stringf("pp_buf_%d_driven_by_fa_row_%d", cpa_ix, fa_row_ix)), + fa_sum_n[(fa_row_ix * fa_count) + 0], Z[cpa_ix]); cpa_ix++; - buf_name = "pp_buf_" + std::to_string(cpa_ix) + "_" + "driven_by_fa_row_" + std::to_string(fa_row_ix) + "_"; - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, fa_sum_n[(fa_row_ix * fa_count) + 1]); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, Z[cpa_ix]); + module->addBufGate(NEW_ID_SUFFIX(stringf("pp_buf_%d_driven_by_fa_row_%d", cpa_ix, fa_row_ix)), + fa_sum_n[(fa_row_ix * fa_count) + 1], Z[cpa_ix]); } else { int offset = fa_row_count * 2; bool base_case = cpa_ix - offset == 0 ? true : false; - std::string cpa_name = "cpa_" + std::to_string(cpa_ix - offset) + "_"; + std::string cpa_name = stringf("cpa_%d", cpa_ix - offset); SigBit ci; if (base_case) From 7179e4f4b89bfea706fbeeff13722a0417bed766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 25 Sep 2023 14:44:45 +0200 Subject: [PATCH 066/173] booth: Improve user interface --- passes/techmap/booth.cc | 49 +++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index aa5684b7427..b81225d0783 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -912,9 +912,7 @@ struct BoothPassWorker { int fa_count = x_sz + 4; int fa_row_count = enc_count - 1; - log("Signed multiplier generator using low Power Negative First Booth Algorithm. Multiplicand of size %d Multiplier of size %d. " - "Result of size %d. %d encoders %d decoders\n", - x_sz, y_sz, z_sz, enc_count, dec_count); + log_debug("Mapping %d x %d -> %d multiplier: %d encoders %d decoders\n", x_sz, y_sz, z_sz, enc_count, dec_count); SigSpec negi_n_int, twoi_n_int, onei_n_int, cori_n_int; @@ -1225,18 +1223,51 @@ struct BoothPassWorker { }; struct BoothPass : public Pass { - BoothPass() : Pass("booth", "Map $mul to booth multipliers") {} + BoothPass() : Pass("booth", "map $mul cells to Booth multipliers") {} + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" booth [selection]\n"); + log("\n"); + log("This pass replaces multiplier cells with an implementation based on the Booth\n"); + log("algorithm. It operates on $mul cells whose width of operands is at least 4x4\n"); + log("and whose width of result is at least 8. The detailed architecture is selected\n"); + log("from two options based on the signedness of the operands to the $mul cell.\n"); + log("\n"); + log("See the references below for the description of the architectures.\n"); + log("\n"); + log("Signed-multiplier architecture:\n"); + log("Y. J. Chang, Y. C. Cheng, S. C. Liao and C. H. Hsiao, \"A Low Power Radix-4 Booth\n"); + log("Multiplier With Pre-Encoded Mechanism,\" in IEEE Access, vol. 8, pp. 114842-114853,\n"); + log("2020, doi: 10.1109/ACCESS.2020.3003684\n"); + log("\n"); + log("Unsigned-multiplier architecture:\n"); + log("G. W. Bewick, \"Fast Multiplication: Algorithms and Implementations,\" PhD Thesis,\n"); + log("Department of Electrical Engineering, Stanford University, 1994\n"); + log("\n"); + } void execute(vector args, RTLIL::Design *design) override { - (void)args; - log_header(design, - "Executing booth pass. Generating Booth Multiplier structures for signed/unsigned multipliers of 4 bits or more\n"); - for (auto mod : design->selected_modules()) + log_header(design, "Executing BOOTH pass (map to Booth multipliers).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + break; + } + extra_args(args, argidx, design); + + int total = 0; + + for (auto mod : design->selected_modules()) { if (!mod->has_processes_warn()) { BoothPassWorker worker(mod); worker.run(); - log_header(design, "Created %d booth multipliers.\n", worker.booth_counter); + total += worker.booth_counter; } + } + + log("Mapped %d multipliers.\n", total); } } MultPass; From 91bcf81dbda538ddb23a992eedc6c3ec67bcec56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 25 Sep 2023 14:45:56 +0200 Subject: [PATCH 067/173] booth: Note down debug prints are broken --- passes/techmap/booth.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index b81225d0783..be38c8fc39f 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -52,6 +52,9 @@ or in generic synthesis call with -booth argument: synth -top my_design -booth */ +//FIXME: These debug prints are broken now, should be fixed or removed. +//#define DEBUG_CPA + #include "kernel/sigtools.h" #include "kernel/yosys.h" From 3319fdc46e3a66690b6a90ad5e47d8a665310984 Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Mon, 25 Sep 2023 17:20:16 +0200 Subject: [PATCH 068/173] show: use dot for wire aliases instead of BUF --- passes/cmds/show.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc index 0dc5c452c09..d57cbc6bb49 100644 --- a/passes/cmds/show.cc +++ b/passes/cmds/show.cc @@ -575,7 +575,7 @@ struct ShowWorker } else { net_conn_map[right_node].in.insert({stringf("x%d", single_idx_count), GetSize(conn.first)}); net_conn_map[left_node].out.insert({stringf("x%d", single_idx_count), GetSize(conn.first)}); - fprintf(f, "x%d [shape=box, style=rounded, label=\"BUF\", %s];\n", single_idx_count++, findColor(conn).c_str()); + fprintf(f, "x%d [shape=point, %s];\n", single_idx_count++, findColor(conn).c_str()); } } } From 10d0e69588a64c0ef451b54d42e8741e4be260e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 4 Apr 2023 20:52:30 +0200 Subject: [PATCH 069/173] ast/simplify: Make tweaks in advance of big in_lvalue/in_param change The following commit will replace the way in_lvalue/in_param is being tracked in the simplify code. Make tweaks in advance so that it will be easier to make the old way and the new way agree. These changes all should be innocuous. --- frontends/ast/simplify.cc | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index ee1be3781c8..7f2b76af090 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -47,7 +47,7 @@ Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_ std::vector args; for (size_t index = first_arg_at; index < children.size(); index++) { AstNode *node_arg = children[index]; - while (node_arg->simplify(true, false, stage, -1, false, false)) { } + while (node_arg->simplify(true, false, stage, -1, false, in_param)) { } VerilogFmtArg arg = {}; arg.filename = filename; @@ -91,7 +91,7 @@ void AstNode::annotateTypedEnums(AstNode *template_node) log_assert(current_scope.count(enum_type) == 1); AstNode *enum_node = current_scope.at(enum_type); log_assert(enum_node->type == AST_ENUM); - while (enum_node->simplify(true, false, 1, -1, false, true)) { } + while (enum_node->simplify(true, false, 1, -1, false, false)) { } //get width from 1st enum item: log_assert(enum_node->children.size() >= 1); AstNode *enum_item0 = enum_node->children[0]; @@ -457,7 +457,8 @@ static int get_max_offset(AstNode *node) static AstNode *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); + int offset = get_max_offset(template_node); + auto wnode = new AstNode(AST_WIRE, make_range(offset, 0)); wnode->str = name; wnode->is_logic = true; wnode->range_valid = true; @@ -465,9 +466,6 @@ static AstNode *make_packed_struct(AstNode *template_node, std::string &name, de for (auto &pair : attributes) { wnode->attributes[pair.first] = pair.second->clone(); } - int offset = get_max_offset(template_node); - auto range = make_range(offset, 0); - wnode->children.push_back(range); // make sure this node is the one in scope for this name current_scope[name] = wnode; // add all the struct members to scope under the wire's name @@ -980,7 +978,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin // when $display()/$write() functions are used in an always block, simplify the expressions and // convert them to a special cell later in genrtlil for (auto node : children) - while (node->simplify(true, false, stage, -1, false, false)) {} + while (node->simplify(true, false, stage, -1, false, in_param)) {} return false; } @@ -1806,7 +1804,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *template_node = resolved_type_node->children[0]; // Ensure typedef itself is fully simplified - while (template_node->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param)) {}; + while (template_node->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, false)) {}; if (!str.empty() && str[0] == '\\' && (template_node->type == AST_STRUCT || template_node->type == AST_UNION)) { // replace instance with wire representing the packed structure @@ -1871,7 +1869,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *template_node = resolved_type_node->children[0]; // Ensure typedef itself is fully simplified - while (template_node->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param)) {}; + while (template_node->simplify(const_fold, false, stage, width_hint, sign_hint, false)) {}; if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) { // replace with wire representing the packed structure @@ -2761,7 +2759,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (children[0]->id2ast->attributes.count(ID::nowrshmsk)) { AstNode *node = children[0]->id2ast->attributes.at(ID::nowrshmsk); - while (node->simplify(true, false, stage, -1, false, false)) { } + while (node->simplify(true, false, stage, -1, false, true)) { } if (node->type != AST_CONSTANT) input_error("Non-constant value for `nowrshmsk' attribute on `%s'!\n", children[0]->id2ast->str.c_str()); if (node->asAttrConst().as_bool()) @@ -3582,7 +3580,7 @@ skip_dynamic_range_lvalue_expansion:; } if (children.size() >= 1) { - while (children[0]->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (children[0]->simplify(true, false, stage, width_hint, sign_hint, in_param)) { } if (!children[0]->isConst()) input_error("Failed to evaluate system function `%s' with non-constant argument.\n", RTLIL::unescape_id(str).c_str()); @@ -3593,7 +3591,7 @@ skip_dynamic_range_lvalue_expansion:; } if (children.size() >= 2) { - while (children[1]->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (children[1]->simplify(true, false, stage, width_hint, sign_hint, in_param)) { } if (!children[1]->isConst()) input_error("Failed to evaluate system function `%s' with non-constant argument.\n", RTLIL::unescape_id(str).c_str()); @@ -3650,7 +3648,7 @@ skip_dynamic_range_lvalue_expansion:; // Determine which bits to count for (size_t i = 1; i < children.size(); i++) { AstNode *node = children[i]; - while (node->simplify(true, false, stage, -1, false, false)) { } + while (node->simplify(true, false, stage, -1, false, in_param)) { } if (node->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant control bit argument.\n", str.c_str()); if (node->bits.size() != 1) @@ -3855,7 +3853,7 @@ skip_dynamic_range_lvalue_expansion:; bool require_const_eval = decl->has_const_only_constructs(); bool all_args_const = true; for (auto child : children) { - while (child->simplify(true, false, 1, -1, false, true)) { } + while (child->simplify(true, in_lvalue, 1, -1, false, in_param)) { } if (child->type != AST_CONSTANT && child->type != AST_REALVALUE) all_args_const = false; } @@ -4048,7 +4046,7 @@ skip_dynamic_range_lvalue_expansion:; } } // updates the sizing - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, false, 1, -1, false, true)) { } delete arg; continue; } From 22b99413e8e22147aeb8a6492c21b456d56a9a90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 5 Apr 2023 11:00:07 +0200 Subject: [PATCH 070/173] ast/simplify: Make in_lvalue/in_param into props of AST nodes Instead of passing around in_lvalue/in_param flags to simplify, we make the flags into properties of the AST nodes themselves. After the tree is first parsed, we once do ast->fixup_hierarchy_flags(true) to walk the full hierarchy and set the flags to their initial correct values. Then as long as one is using ->clone(), ->cloneInto() and the AstNode constructor (with children passed to it) to modify the tree, the flags will be kept in sync automatically. On the other hand if we are modifying the children list of an existing node, we may need to call node->fixup_hierarchy_flags() to do a localized fixup. That fixup will update the flags on the node's children, and will propagate the change down the tree if necessary. clone() doesn't always retain the flags of the subtree being cloned. It will produce a tree with a consistent setting of the flags, but the root doesn't have in_param/in_lvalue set unless it's intrinsic to the type of node being cloned (e.g. AST_PARAMETER). cloneInto() will make sure the cloned subtree has the flags consistent with the new placement in a hierarchy. Add asserts to make sure the old and new way of determining the flags agree. --- frontends/ast/ast.cc | 26 ++++- frontends/ast/ast.h | 25 +++++ frontends/ast/genrtlil.cc | 11 ++- frontends/ast/simplify.cc | 202 +++++++++++++++++++++++++++++++------- 4 files changed, 222 insertions(+), 42 deletions(-) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index a027295e979..5a5851c3e6b 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -229,6 +229,10 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch id2ast = NULL; basic_prep = false; lookahead = false; + in_lvalue_from_above = false; + in_param_from_above = false; + in_lvalue = false; + in_param = false; if (child1) children.push_back(child1); @@ -238,6 +242,8 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch children.push_back(child3); if (child4) children.push_back(child4); + + fixup_hierarchy_flags(); } // create a (deep recursive) copy of a node @@ -249,6 +255,10 @@ AstNode *AstNode::clone() const 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 return that; } @@ -256,10 +266,13 @@ AstNode *AstNode::clone() 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; } @@ -351,6 +364,10 @@ void AstNode::dumpAst(FILE *f, std::string indent) const if (is_enum) { fprintf(f, " type=enum"); } + if (in_lvalue) + fprintf(f, " in_lvalue"); + if (in_param) + fprintf(f, " in_param"); fprintf(f, "\n"); for (auto &it : attributes) { @@ -1091,7 +1108,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d ast->attributes.erase(ID::whitebox); } AstNode *n = ast->attributes.at(ID::lib_whitebox); - ast->attributes[ID::whitebox] = n; + ast->set_attribute(ID::whitebox, n); ast->attributes.erase(ID::lib_whitebox); } } @@ -1150,7 +1167,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->attributes[ID::blackbox] = AstNode::mkconst_int(1, false); + ast->set_attribute(ID::blackbox, AstNode::mkconst_int(1, false)); } } @@ -1298,6 +1315,8 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump flag_pwires = pwires; flag_autowire = autowire; + ast->fixup_hierarchy_flags(true); + log_assert(current_ast->type == AST_DESIGN); for (AstNode *child : current_ast->children) { @@ -1748,7 +1767,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictclone(); if (!new_ast->attributes.count(ID::hdlname)) - new_ast->attributes[ID::hdlname] = AstNode::mkconst_str(stripped_name); + new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(stripped_name)); para_counter = 0; for (auto child : new_ast->children) { @@ -1795,6 +1814,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictchildren.push_back(defparam); } + new_ast->fixup_hierarchy_flags(true); (*new_ast_out) = new_ast; return modname; } diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index e357579add2..cd6e254215a 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -221,6 +221,13 @@ namespace AST std::string filename; AstSrcLocType location; + // are we embedded in an lvalue, param? + // (see fixup_hierarchy_flags) + bool in_lvalue; + bool in_param; + bool in_lvalue_from_above; + 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; @@ -343,6 +350,24 @@ namespace AST // to evaluate widths of dynamic ranges) AstNode *clone_at_zero(); + void set_attribute(RTLIL::IdString key, AstNode *node) + { + attributes[key] = node; + node->set_in_param_flag(true); + } + + // helper to set in_lvalue/in_param flags from the hierarchy context (the actual flag + // can be overridden based on the intrinsic properties of this node, i.e. based on its type) + void set_in_lvalue_flag(bool flag, bool no_descend = false); + void set_in_param_flag(bool flag, bool no_descend = false); + + // fix up the hierarchy flags (in_lvalue/in_param) of this node and its children + // + // to keep the flags in sync, fixup_hierarchy_flags(true) needs to be called once after + // parsing the AST to walk the full tree, then plain fixup_hierarchy_flags() performs + // localized fixups after modifying children/attributes of a particular node + void fixup_hierarchy_flags(bool force_descend = false); + // helper to print errors from simplify/genrtlil code [[noreturn]] void input_error(const char *format, ...) const YS_ATTRIBUTE(format(printf, 2, 3)); }; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index d62f06ae549..64626d9a966 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -176,8 +176,9 @@ struct AST_INTERNAL::LookaheadRewriter AstNode *wire = new AstNode(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->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire->is_logic = true; while (wire->simplify(true, false, 1, -1, false, false)) { } current_ast_mod->children.push_back(wire); @@ -1198,8 +1199,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun log_assert(range->type == AST_RANGE && range->children.size() == 2); AstNode *left = range->children.at(0)->clone(); AstNode *right = range->children.at(1)->clone(); - while (left->simplify(true, false, 1, -1, false, true)) { } - while (right->simplify(true, false, 1, -1, false, true)) { } + left->set_in_param_flag(true); + right->set_in_param_flag(true); + while (left->simplify(true, in_lvalue, 1, -1, false, true)) { } + while (right->simplify(true, in_lvalue, 1, -1, false, true)) { } if (left->type != AST_CONSTANT || right->type != AST_CONSTANT) input_error("Function %s has non-constant width!", RTLIL::unescape_id(str).c_str()); @@ -1552,7 +1555,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) children[0]->children[1]->clone() : children[0]->children[0]->clone()); fake_ast->children[0]->delete_children(); if (member_node) - fake_ast->children[0]->attributes[ID::wiretype] = member_node->clone(); + fake_ast->children[0]->set_attribute(ID::wiretype, member_node->clone()); int fake_ast_width = 0; bool fake_ast_sign = true; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 7f2b76af090..4583f770b2c 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -41,6 +41,95 @@ YOSYS_NAMESPACE_BEGIN using namespace AST; using namespace AST_INTERNAL; +void AstNode::set_in_lvalue_flag(bool flag, bool no_descend) +{ + if (flag != in_lvalue_from_above) { + in_lvalue_from_above = flag; + if (!no_descend) + fixup_hierarchy_flags(); + } +} + +void AstNode::set_in_param_flag(bool flag, bool no_descend) +{ + if (flag != in_param_from_above) { + in_param_from_above = flag; + if (!no_descend) + fixup_hierarchy_flags(); + } +} + +void AstNode::fixup_hierarchy_flags(bool force_descend) +{ + // With forced descend, we disable the implicit + // descend from within the set_* functions, instead + // we do an explicit descend at the end of this function + + in_param = in_param_from_above; + + switch (type) { + case AST_PARAMETER: + case AST_LOCALPARAM: + case AST_DEFPARAM: + case AST_PARASET: + case AST_PREFIX: + in_param = true; + for (auto child : children) + child->set_in_param_flag(true, force_descend); + break; + + case AST_REPLICATE: + case AST_WIRE: + case AST_GENIF: + case AST_GENCASE: + 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); + break; + + case AST_GENFOR: + case AST_FOR: + for (auto child : children) + 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) + child->set_in_param_flag(in_param, force_descend); + } + + for (auto attr : attributes) + attr.second->set_in_param_flag(true, force_descend); + + in_lvalue = in_lvalue_from_above; + + switch (type) { + case AST_ASSIGN: + case AST_ASSIGN_EQ: + case AST_ASSIGN_LE: + if (children.size() >= 1) + children[0]->set_in_lvalue_flag(true, force_descend); + if (children.size() >= 2) + children[1]->set_in_lvalue_flag(in_lvalue, force_descend); + break; + + default: + for (auto child : children) + child->set_in_lvalue_flag(in_lvalue, force_descend); + } + + if (force_descend) { + for (auto child : children) + child->fixup_hierarchy_flags(true); + for (auto attr : attributes) + attr.second->fixup_hierarchy_flags(true); + } +} + // Process a format string and arguments for $display, $write, $sprintf, etc Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_t first_arg_at) { @@ -132,7 +221,7 @@ 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 - attributes[enum_item_str.c_str()] = mkconst_str(enum_item->str); + set_attribute(enum_item_str.c_str(), mkconst_str(enum_item->str)); } } } @@ -464,7 +553,7 @@ static AstNode *make_packed_struct(AstNode *template_node, std::string &name, de wnode->range_valid = true; wnode->is_signed = template_node->is_signed; for (auto &pair : attributes) { - wnode->attributes[pair.first] = pair.second->clone(); + wnode->set_attribute(pair.first, pair.second->clone()); } // make sure this node is the one in scope for this name current_scope[name] = wnode; @@ -525,7 +614,7 @@ const RTLIL::Module* AstNode::lookup_cell_module() auto reprocess_after = [this] (const std::string &modname) { if (!attributes.count(ID::reprocess_after)) - attributes[ID::reprocess_after] = AstNode::mkconst_str(modname); + set_attribute(ID::reprocess_after, AstNode::mkconst_str(modname)); }; const AstNode *celltype = nullptr; @@ -705,6 +794,11 @@ AstNode *AstNode::clone_at_zero() it = it->clone_at_zero(); 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(); + return that; } @@ -743,8 +837,7 @@ static void mark_auto_nosync(AstNode *block, const AstNode *wire) { log_assert(block->type == AST_BLOCK); log_assert(wire->type == AST_WIRE); - block->attributes[auto_nosync_prefix + wire->str] = AstNode::mkconst_int(1, - false); + block->set_attribute(auto_nosync_prefix + wire->str, AstNode::mkconst_int(1, false)); } // block names can be prefixed with an explicit scope during elaboration @@ -785,7 +878,7 @@ static void check_auto_nosync(AstNode *node) // mark the wire with `nosync` AstNode *wire = it->second; log_assert(wire->type == AST_WIRE); - wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); } // remove the attributes we've "consumed" @@ -806,7 +899,7 @@ static void check_auto_nosync(AstNode *node) // // this function also does all name resolving and sets the id2ast member of all // nodes that link to a different node using names and lexical scoping. -bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param) +bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hint, bool sign_hint, bool in_param_) { static int recursion_counter = 0; static bool deep_recursion_warning = false; @@ -913,7 +1006,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin reg->is_signed = node->is_signed; for (auto &it : node->attributes) if (it.first != ID::mem2reg) - reg->attributes.emplace(it.first, it.second->clone()); + reg->set_attribute(it.first, it.second->clone()); reg->filename = node->filename; reg->location = node->location; children.push_back(reg); @@ -994,7 +1087,9 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin // in certain cases a function must be evaluated constant. this is what in_param controls. if (type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_PREFIX) - in_param = true; + in_param_ = true; + log_assert(in_param == in_param_); + log_assert(in_lvalue == in_lvalue_); std::map backup_scope; @@ -1015,7 +1110,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (!c->is_simple_const_expr()) { if (attributes.count(ID::dynports)) delete attributes.at(ID::dynports); - attributes[ID::dynports] = AstNode::mkconst_int(1, true); + set_attribute(ID::dynports, AstNode::mkconst_int(1, true)); } } } @@ -1064,7 +1159,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin for (auto &it : node->attributes) { if (first_node->attributes.count(it.first) > 0) delete first_node->attributes[it.first]; - first_node->attributes[it.first] = it.second->clone(); + first_node->set_attribute(it.first, it.second->clone()); } children.erase(children.begin()+(i--)); did_something = true; @@ -1261,6 +1356,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin asgn->children.push_back(arg); asgn->children.push_back(ident); } + asgn->fixup_hierarchy_flags(); } @@ -1382,7 +1478,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin range_left = template_node->range_left; range_right = template_node->range_right; - attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); + set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); // Copy clones of children from template for (auto template_child : template_node->children) { @@ -1414,7 +1510,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (children[0]->type == AST_IDENTIFIER && current_scope.count(children[0]->str) > 0) { auto item_node = current_scope[children[0]->str]; if (item_node->type == AST_STRUCT || item_node->type == AST_UNION) { - attributes[ID::wiretype] = item_node->clone(); + set_attribute(ID::wiretype, item_node->clone()); size_packed_struct(attributes[ID::wiretype], 0); add_members_to_scope(attributes[ID::wiretype], str); } @@ -1809,7 +1905,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_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); - newNode->attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); + 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; newNode->is_output = this->is_output; @@ -1834,7 +1930,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin range_left = template_node->range_left; range_right = template_node->range_right; - attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); + set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); // if an enum then add attributes to support simulator tracing annotateTypedEnums(template_node); @@ -1848,6 +1944,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *rng = make_range(0, 0); children.insert(children.begin(), rng); } + fixup_hierarchy_flags(); did_something = true; } log_assert(!is_custom_type); @@ -1874,7 +1971,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) { // replace with wire representing the packed structure newNode = make_packed_struct(template_node, str, attributes); - newNode->attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); + newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); newNode->type = type; current_scope[str] = this; // copy param value, it needs to be 1st value @@ -1896,9 +1993,10 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin range_swapped = template_node->range_swapped; range_left = template_node->range_left; range_right = template_node->range_right; - attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); + set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); for (auto template_child : template_node->children) children.push_back(template_child->clone()); + fixup_hierarchy_flags(); did_something = true; } log_assert(!is_custom_type); @@ -2018,6 +2116,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin } delete children[1]; children[1] = new AstNode(AST_RANGE, AstNode::mkconst_int(0, true), AstNode::mkconst_int(total_size-1, true)); + fixup_hierarchy_flags(); did_something = true; } @@ -2052,6 +2151,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin else children[0] = new AstNode(AST_RANGE, index_expr); + fixup_hierarchy_flags(); did_something = true; } @@ -2067,6 +2167,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin children[0]->realvalue, log_signal(constvalue)); delete children[0]; children[0] = mkconst_bits(constvalue.bits, sign_hint); + fixup_hierarchy_flags(); did_something = true; } if (children[0]->type == AST_CONSTANT) { @@ -2076,6 +2177,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *old_child_0 = children[0]; children[0] = mkconst_bits(sig.as_const().bits, is_signed); delete old_child_0; + fixup_hierarchy_flags(); } children[0]->is_signed = is_signed; } @@ -2089,6 +2191,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin delete children[0]; children[0] = new AstNode(AST_REALVALUE); children[0]->realvalue = as_realvalue; + fixup_hierarchy_flags(); did_something = true; } } @@ -2105,7 +2208,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin newNode = new AstNode(AST_IDENTIFIER, range); newNode->str = sname; // save type and original number of dimensions for $size() etc. - newNode->attributes[ID::wiretype] = item_node->clone(); + newNode->set_attribute(ID::wiretype, item_node->clone()); if (!item_node->multirange_dimensions.empty() && children.size() > 0) { if (children[0]->type == AST_RANGE) newNode->integer = 1; @@ -2199,7 +2302,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); wire->str = wire_id; if (current_block) - wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); current_ast_mod->children.push_back(wire); while (wire->simplify(true, false, 1, -1, false, false)) { } @@ -2387,6 +2490,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin // eval 3rd expression buf = next_ast->children[1]->clone(); + buf->set_in_param_flag(true); { int expr_width_hint = -1; bool expr_sign_hint = true; @@ -2548,6 +2652,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin continue; buf = child->clone(); + buf->set_in_param_flag(true); while (buf->simplify(true, false, stage, width_hint, sign_hint, true)) { } if (buf->type != AST_CONSTANT) { // for (auto f : log_files) @@ -2654,6 +2759,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin children.push_back(children_list.at(0)); children.back()->was_checked = true; children.push_back(node); + fixup_hierarchy_flags(); did_something = true; } else if (str == "buf" || str == "not") @@ -2704,6 +2810,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin children.push_back(children_list[0]); children.back()->was_checked = true; children.push_back(node); + fixup_hierarchy_flags(); did_something = true; } } @@ -2782,7 +2889,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *lvalue = children[0]->clone(); lvalue->delete_children(); if (member_node) - lvalue->attributes[ID::wiretype] = member_node->clone(); + lvalue->set_attribute(ID::wiretype, member_node->clone()); lvalue->children.push_back(new AstNode(AST_RANGE, mkconst_int(end_bit, true), mkconst_int(start_bit, true))); cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone()))); @@ -2795,14 +2902,14 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *wire_mask = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); - wire_mask->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_mask->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire_mask->is_logic = true; while (wire_mask->simplify(true, false, 1, -1, false, false)) { } current_ast_mod->children.push_back(wire_mask); AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); - wire_data->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire_data->is_logic = true; while (wire_data->simplify(true, false, 1, -1, false, false)) { } current_ast_mod->children.push_back(wire_data); @@ -2813,7 +2920,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *wire_sel = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(shamt_width_hint-1, true), mkconst_int(0, true))); wire_sel->str = stringf("$bitselwrite$sel$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); - wire_sel->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_sel->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire_sel->is_logic = true; wire_sel->is_signed = shamt_sign_hint; while (wire_sel->simplify(true, false, 1, -1, false, false)) { } @@ -2825,7 +2932,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *lvalue = children[0]->clone(); lvalue->delete_children(); if (member_node) - lvalue->attributes[ID::wiretype] = member_node->clone(); + lvalue->set_attribute(ID::wiretype, member_node->clone()); AstNode *ref_mask = new AstNode(AST_IDENTIFIER); ref_mask->str = wire_mask->str; @@ -2882,6 +2989,8 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin t = new AstNode(AST_BIT_OR, t, ref_data); t = new AstNode(type, lvalue, t); newNode->children.push_back(t); + + newNode->fixup_hierarchy_flags(true); } goto apply_newNode; @@ -2942,6 +3051,7 @@ skip_dynamic_range_lvalue_expansion:; assign_check->children[0]->str = id_check; assign_check->children[0]->was_checked = true; } + assign_check->fixup_hierarchy_flags(); if (current_always == nullptr || current_always->type != AST_INITIAL) { assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1)); @@ -2951,6 +3061,7 @@ skip_dynamic_range_lvalue_expansion:; } assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; + assign_en->fixup_hierarchy_flags(); newNode = new AstNode(AST_BLOCK); if (assign_check != nullptr) @@ -2973,6 +3084,7 @@ skip_dynamic_range_lvalue_expansion:; if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME || type == AST_LIVE || type == AST_FAIR || type == AST_COVER) && children.size() == 1) { children.push_back(mkconst_int(1, false, 1)); + fixup_hierarchy_flags(); did_something = true; } @@ -3003,7 +3115,7 @@ skip_dynamic_range_lvalue_expansion:; 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; - wire_tmp->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_tmp->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); while (wire_tmp->simplify(true, false, 1, -1, false, false)) { } wire_tmp->is_logic = true; @@ -3743,6 +3855,7 @@ skip_dynamic_range_lvalue_expansion:; argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str)); args.push_back(children.at(i-2)->clone()); + args.back()->set_in_param_flag(true); while (args.back()->simplify(true, false, stage, -1, false, true)) { } if (args.back()->type != AST_CONSTANT && args.back()->type != AST_REALVALUE) @@ -3860,6 +3973,7 @@ skip_dynamic_range_lvalue_expansion:; if (all_args_const) { AstNode *func_workspace = decl->clone(); + func_workspace->set_in_param_flag(true); func_workspace->str = prefix_id(prefix, "$result"); newNode = func_workspace->eval_const_function(this, in_param || require_const_eval); delete func_workspace; @@ -4004,9 +4118,9 @@ skip_dynamic_range_lvalue_expansion:; wire->is_input = false; wire->is_output = false; wire->is_reg = true; - wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); if (child->type == AST_ENUM_ITEM) - wire->attributes[ID::enum_base_type] = child->attributes[ID::enum_base_type]; + wire->set_attribute(ID::enum_base_type, child->attributes[ID::enum_base_type]); wire_cache[child->str] = wire; @@ -4045,6 +4159,7 @@ skip_dynamic_range_lvalue_expansion:; range->children.push_back(mkconst_int(0, true)); } } + wire->fixup_hierarchy_flags(); // updates the sizing while (wire->simplify(true, false, 1, -1, false, true)) { } delete arg; @@ -4364,6 +4479,7 @@ replace_fcall_later:; newNode->filename = filename; newNode->location = location; newNode->cloneInto(this); + fixup_hierarchy_flags(); delete newNode; did_something = true; } @@ -4954,7 +5070,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, wire_addr->str = id_addr; wire_addr->is_reg = true; wire_addr->was_checked = true; - wire_addr->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_addr); while (wire_addr->simplify(true, false, 1, -1, false, false)) { } @@ -4963,7 +5079,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, wire_data->is_reg = true; wire_data->was_checked = true; wire_data->is_signed = mem_signed; - wire_data->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_data); while (wire_data->simplify(true, false, 1, -1, false, false)) { } @@ -4992,6 +5108,10 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, cond_node->children[1]->children.push_back(assign_reg); case_node->children.push_back(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); children[0]->delete_children(); @@ -5001,6 +5121,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, type = AST_ASSIGN_EQ; children[0]->was_checked = true; + fixup_hierarchy_flags(); did_something = true; } @@ -5071,7 +5192,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, wire_addr->is_reg = true; wire_addr->was_checked = true; if (block) - wire_addr->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_addr); while (wire_addr->simplify(true, false, 1, -1, false, false)) { } @@ -5081,7 +5202,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, wire_data->was_checked = true; wire_data->is_signed = mem_signed; if (block) - wire_data->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_data); while (wire_data->simplify(true, false, 1, -1, false, false)) { } @@ -5115,6 +5236,9 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, cond_node->children[1]->children.push_back(assign_reg); case_node->children.push_back(cond_node); + // fixup on the full hierarchy below case_node + case_node->fixup_hierarchy_flags(true); + if (block) { size_t assign_idx = 0; @@ -5126,10 +5250,10 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, } else { - AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK)); - proc->children[0]->children.push_back(case_node); + AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK, case_node)); mod->children.push_back(proc); mod->children.push_back(assign_addr); + mod->fixup_hierarchy_flags(); } delete_children(); @@ -5138,8 +5262,10 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, str = id_data; } - if (bit_part_sel) + if (bit_part_sel) { children.push_back(bit_part_sel); + fixup_hierarchy_flags(); + } did_something = true; } @@ -5302,6 +5428,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) { block->children.push_back(child->clone()); } + block->set_in_param_flag(true); while (!block->children.empty()) { @@ -5444,6 +5571,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) AstNode *cond = stmt->children.at(0)->clone(); if (!cond->replace_variables(variables, fcall, must_succeed)) goto finished; + cond->set_in_param_flag(true); while (cond->simplify(true, false, 1, -1, false, true)) { } if (cond->type != AST_CONSTANT) { @@ -5469,6 +5597,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) AstNode *num = stmt->children.at(0)->clone(); if (!num->replace_variables(variables, fcall, must_succeed)) goto finished; + num->set_in_param_flag(true); while (num->simplify(true, false, 1, -1, false, true)) { } if (num->type != AST_CONSTANT) { @@ -5492,6 +5621,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) AstNode *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, false, 1, -1, false, true)) { } AstNode *sel_case = NULL; @@ -5512,6 +5642,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) goto finished; cond = new AstNode(AST_EQ, expr->clone(), cond); + cond->set_in_param_flag(true); while (cond->simplify(true, false, 1, -1, false, true)) { } if (cond->type != AST_CONSTANT) { @@ -5547,6 +5678,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) block->children.erase(block->children.begin()); block->children.insert(block->children.begin(), stmt->children.begin(), stmt->children.end()); stmt->children.clear(); + block->fixup_hierarchy_flags(); delete stmt; continue; } @@ -5581,7 +5713,7 @@ void AstNode::allocateDefaultEnumValues() int last_enum_int = -1; for (auto node : children) { log_assert(node->type==AST_ENUM_ITEM); - node->attributes[ID::enum_base_type] = mkconst_str(str); + 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: From a511976b489ab266a511b9d8d96ee7e5001c9306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 4 Apr 2023 22:59:44 +0200 Subject: [PATCH 071/173] ast/simplify: Retire in_lvalue/in_param arguments to simplify --- frontends/ast/ast.cc | 4 +- frontends/ast/ast.h | 2 +- frontends/ast/genrtlil.cc | 26 ++--- frontends/ast/simplify.cc | 197 ++++++++++++++++++-------------------- 4 files changed, 110 insertions(+), 119 deletions(-) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 5a5851c3e6b..5335a3992d6 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1078,7 +1078,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d // simplify this module or interface using the current design as context // for lookup up ports and wires within cells set_simplify_design_context(design); - while (ast->simplify(!flag_noopt, false, 0, -1, false, false)) { } + while (ast->simplify(!flag_noopt, 0, -1, false)) { } set_simplify_design_context(nullptr); if (flag_dump_ast2) { @@ -1380,7 +1380,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump } else if (child->type == AST_PACKAGE) { // process enum/other declarations - child->simplify(true, false, 1, -1, false, false); + child->simplify(true, 1, -1, false); rename_in_package_stmts(child); design->verilog_packages.push_back(child->clone()); current_scope.clear(); diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index cd6e254215a..f789e930b3e 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -258,7 +258,7 @@ 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, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param); + bool simplify(bool const_fold, int stage, int width_hint, bool sign_hint); 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); void expand_genblock(const std::string &prefix); diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 64626d9a966..6e750863fbe 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -180,7 +180,7 @@ struct AST_INTERNAL::LookaheadRewriter 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, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } current_ast_mod->children.push_back(wire); lookaheadids[node->str] = make_pair(node->id2ast, wire); wire->genRTLIL(); @@ -927,7 +927,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1; } else { if (id_ast->children[0]->type != AST_CONSTANT) - while (id_ast->simplify(true, false, 1, -1, false, true)) { } + while (id_ast->simplify(true, 1, -1, false)) { } if (id_ast->children[0]->type == AST_CONSTANT) this_width = id_ast->children[0]->bits.size(); else @@ -971,8 +971,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun 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(); - while (left_at_zero_ast->simplify(true, false, 1, -1, false, false)) { } - while (right_at_zero_ast->simplify(true, false, 1, -1, false, false)) { } + 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; @@ -988,7 +988,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun break; case AST_TO_BITS: - while (children[0]->simplify(true, false, 1, -1, false, false) == true) { } + while (children[0]->simplify(true, 1, -1, false) == true) { } if (children[0]->type != AST_CONSTANT) input_error("Left operand of tobits expression is not constant!\n"); children[1]->detectSignWidthWorker(sub_width_hint, sign_hint); @@ -1010,7 +1010,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun break; case AST_CAST_SIZE: - while (children.at(0)->simplify(true, false, 1, -1, false, false)) { } + while (children.at(0)->simplify(true, 1, -1, false)) { } if (children.at(0)->type != AST_CONSTANT) input_error("Static cast with non constant expression!\n"); children.at(1)->detectSignWidthWorker(width_hint, sign_hint); @@ -1032,7 +1032,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun break; case AST_REPLICATE: - while (children[0]->simplify(true, false, 1, -1, false, true) == true) { } + while (children[0]->simplify(true, 1, -1, false) == true) { } if (children[0]->type != AST_CONSTANT) input_error("Left operand of replicate expression is not constant!\n"); children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint); @@ -1144,7 +1144,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_PREFIX: // Prefix nodes always resolve to identifiers in generate loops, so we // can simply perform the resolution to determine the sign and width. - simplify(true, false, 1, -1, false, false); + simplify(true, 1, -1, false); log_assert(type == AST_IDENTIFIER); detectSignWidthWorker(width_hint, sign_hint, found_real); break; @@ -1152,7 +1152,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_FCALL: if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq") { if (GetSize(children) == 1) { - while (children[0]->simplify(true, false, 1, -1, false, true) == true) { } + while (children[0]->simplify(true, 1, -1, false) == true) { } if (children[0]->type != AST_CONSTANT) input_error("System function %s called with non-const argument!\n", RTLIL::unescape_id(str).c_str()); @@ -1201,8 +1201,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun AstNode *right = range->children.at(1)->clone(); left->set_in_param_flag(true); right->set_in_param_flag(true); - while (left->simplify(true, in_lvalue, 1, -1, false, true)) { } - while (right->simplify(true, in_lvalue, 1, -1, false, true)) { } + while (left->simplify(true, 1, -1, false)) { } + while (right->simplify(true, 1, -1, false)) { } if (left->type != AST_CONSTANT || right->type != AST_CONSTANT) input_error("Function %s has non-constant width!", RTLIL::unescape_id(str).c_str()); @@ -1546,8 +1546,8 @@ 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(); - while (left_at_zero_ast->simplify(true, false, 1, -1, false, false)) { } - while (right_at_zero_ast->simplify(true, false, 1, -1, false, false)) { } + 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; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 4583f770b2c..c4a30302712 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -136,7 +136,7 @@ Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_ std::vector args; for (size_t index = first_arg_at; index < children.size(); index++) { AstNode *node_arg = children[index]; - while (node_arg->simplify(true, false, stage, -1, false, in_param)) { } + while (node_arg->simplify(true, stage, -1, false)) { } VerilogFmtArg arg = {}; arg.filename = filename; @@ -180,7 +180,7 @@ void AstNode::annotateTypedEnums(AstNode *template_node) log_assert(current_scope.count(enum_type) == 1); AstNode *enum_node = current_scope.at(enum_type); log_assert(enum_node->type == AST_ENUM); - while (enum_node->simplify(true, false, 1, -1, false, false)) { } + 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]; @@ -814,8 +814,8 @@ static bool try_determine_range_width(AstNode *range, int &result_width) AstNode *left_at_zero_ast = range->children[0]->clone_at_zero(); AstNode *right_at_zero_ast = range->children[1]->clone_at_zero(); - while (left_at_zero_ast->simplify(true, false, 1, -1, false, false)) {} - while (right_at_zero_ast->simplify(true, false, 1, -1, false, false)) {} + while (left_at_zero_ast->simplify(true, 1, -1, false)) {} + while (right_at_zero_ast->simplify(true, 1, -1, false)) {} bool ok = false; if (left_at_zero_ast->type == AST_CONSTANT @@ -899,7 +899,7 @@ static void check_auto_nosync(AstNode *node) // // this function also does all name resolving and sets the id2ast member of all // nodes that link to a different node using names and lexical scoping. -bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hint, bool sign_hint, bool in_param_) +bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hint) { static int recursion_counter = 0; static bool deep_recursion_warning = false; @@ -917,8 +917,8 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi #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("const_fold=%d, in_lvalue=%d, stage=%d, width_hint=%d, sign_hint=%d, in_param=%d\n", - int(const_fold), int(in_lvalue), int(stage), int(width_hint), int(sign_hint), int(in_param)); + 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, "> "); #endif @@ -927,7 +927,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi log_assert(type == AST_MODULE || type == AST_INTERFACE); deep_recursion_warning = true; - while (simplify(const_fold, in_lvalue, 1, width_hint, sign_hint, in_param)) { } + while (simplify(const_fold, 1, width_hint, sign_hint)) { } if (!flag_nomem2reg && !get_bool_attribute(ID::nomem2reg)) { @@ -1010,7 +1010,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi reg->filename = node->filename; reg->location = node->location; children.push_back(reg); - while (reg->simplify(true, false, 1, -1, false, false)) { } + while (reg->simplify(true, 1, -1, false)) { } } } @@ -1024,7 +1024,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi delete node; } - while (simplify(const_fold, in_lvalue, 2, width_hint, sign_hint, in_param)) { } + while (simplify(const_fold, 2, width_hint, sign_hint)) { } recursion_counter--; return false; } @@ -1071,7 +1071,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi // when $display()/$write() functions are used in an always block, simplify the expressions and // convert them to a special cell later in genrtlil for (auto node : children) - while (node->simplify(true, false, stage, -1, false, in_param)) {} + while (node->simplify(true, stage, -1, false)) {} return false; } @@ -1085,12 +1085,6 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (type == AST_IDENTIFIER && current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM || current_scope[str]->type == AST_ENUM_ITEM)) const_fold = true; - // in certain cases a function must be evaluated constant. this is what in_param controls. - if (type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_PREFIX) - in_param_ = true; - log_assert(in_param == in_param_); - log_assert(in_lvalue == in_lvalue_); - std::map backup_scope; // create name resolution entries for all objects with names @@ -1193,12 +1187,12 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi for (size_t i = 0; i < children.size(); i++) { AstNode *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, false, 1, -1, false, node->type == AST_PARAMETER || node->type == AST_LOCALPARAM)) + while (node->simplify(true, 1, -1, false)) did_something = true; if (node->type == AST_ENUM) { for (auto enode : node->children){ log_assert(enode->type==AST_ENUM_ITEM); - while (node->simplify(true, false, 1, -1, false, in_param)) + while (node->simplify(true, 1, -1, false)) did_something = true; } } @@ -1263,7 +1257,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi for (AstNode *child : children) { // simplify any parameters to constants if (child->type == AST_PARASET) - while (child->simplify(true, false, 1, -1, false, true)) { } + while (child->simplify(true, 1, -1, false)) { } // look for patterns which _may_ indicate ambiguity requiring // resolution of the underlying module @@ -1378,9 +1372,9 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi case AST_ASSIGN_EQ: case AST_ASSIGN_LE: case AST_ASSIGN: - while (!children[0]->basic_prep && children[0]->simplify(false, true, stage, -1, false, in_param) == true) + while (!children[0]->basic_prep && children[0]->simplify(false, stage, -1, false) == true) did_something = true; - while (!children[1]->basic_prep && children[1]->simplify(false, false, stage, -1, false, in_param) == true) + while (!children[1]->basic_prep && children[1]->simplify(false, stage, -1, false) == true) did_something = true; children[0]->detectSignWidth(backup_width_hint, backup_sign_hint); children[1]->detectSignWidth(width_hint, sign_hint); @@ -1416,7 +1410,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (!basic_prep) { for (auto *node : children) { // resolve any ranges - while (!node->basic_prep && node->simplify(true, false, stage, -1, false, false)) { + while (!node->basic_prep && node->simplify(true, stage, -1, false)) { did_something = true; } } @@ -1449,7 +1443,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi AstNode *template_node = resolved_type_node->children[0]; // Ensure typedef itself is fully simplified - while (template_node->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param)) {}; + while (template_node->simplify(const_fold, stage, width_hint, sign_hint)) {}; // Remove type reference delete children[0]; @@ -1495,7 +1489,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi //log("\nENUM %s: %d child %d\n", str.c_str(), basic_prep, children[0]->basic_prep); if (!basic_prep) { for (auto item_node : children) { - while (!item_node->basic_prep && item_node->simplify(false, false, stage, -1, false, in_param)) + while (!item_node->basic_prep && item_node->simplify(false, stage, -1, false)) did_something = true; } // allocate values (called more than once) @@ -1515,11 +1509,11 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi add_members_to_scope(attributes[ID::wiretype], str); } } - while (!children[0]->basic_prep && children[0]->simplify(false, false, stage, -1, false, true) == true) + while (!children[0]->basic_prep && children[0]->simplify(false, stage, -1, false) == true) did_something = true; children[0]->detectSignWidth(width_hint, sign_hint); if (children.size() > 1 && children[1]->type == AST_RANGE) { - while (!children[1]->basic_prep && children[1]->simplify(false, false, stage, -1, false, true) == true) + while (!children[1]->basic_prep && children[1]->simplify(false, stage, -1, false) == true) did_something = true; if (!children[1]->range_valid) input_error("Non-constant width range on parameter decl.\n"); @@ -1527,11 +1521,11 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi } break; case AST_ENUM_ITEM: - while (!children[0]->basic_prep && children[0]->simplify(false, false, stage, -1, false, in_param)) + while (!children[0]->basic_prep && children[0]->simplify(false, stage, -1, false)) did_something = true; children[0]->detectSignWidth(width_hint, sign_hint); if (children.size() > 1 && children[1]->type == AST_RANGE) { - while (!children[1]->basic_prep && children[1]->simplify(false, false, stage, -1, false, in_param)) + while (!children[1]->basic_prep && children[1]->simplify(false, stage, -1, false)) did_something = true; if (!children[1]->range_valid) input_error("Non-constant width range on enum item decl.\n"); @@ -1590,7 +1584,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi width_hint = -1; sign_hint = true; for (auto child : children) { - while (!child->basic_prep && child->simplify(false, in_lvalue, stage, -1, false, in_param) == true) + while (!child->basic_prep && child->simplify(false, stage, -1, false) == true) did_something = true; child->detectSignWidthWorker(width_hint, sign_hint); } @@ -1625,10 +1619,10 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (detect_width_simple && width_hint < 0) { if (type == AST_REPLICATE) - while (children[0]->simplify(true, in_lvalue, stage, -1, false, true) == true) + while (children[0]->simplify(true, stage, -1, false) == true) did_something = true; for (auto child : children) - while (!child->basic_prep && child->simplify(false, in_lvalue, stage, -1, false, in_param) == true) + while (!child->basic_prep && child->simplify(false, stage, -1, false) == true) did_something = true; detectSignWidth(width_hint, sign_hint); } @@ -1638,18 +1632,18 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (type == AST_TERNARY) { if (width_hint < 0) { - while (!children[0]->basic_prep && children[0]->simplify(true, in_lvalue, stage, -1, false, in_param)) + while (!children[0]->basic_prep && children[0]->simplify(true, stage, -1, false)) did_something = true; bool backup_unevaluated_tern_branch = unevaluated_tern_branch; AstNode *chosen = get_tern_choice().first; unevaluated_tern_branch = backup_unevaluated_tern_branch || chosen == children[2]; - while (!children[1]->basic_prep && children[1]->simplify(false, in_lvalue, stage, -1, false, in_param)) + 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]; - while (!children[2]->basic_prep && children[2]->simplify(false, in_lvalue, stage, -1, false, in_param)) + while (!children[2]->basic_prep && children[2]->simplify(false, stage, -1, false)) did_something = true; unevaluated_tern_branch = backup_unevaluated_tern_branch; @@ -1681,7 +1675,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (const_fold && type == AST_CASE) { detectSignWidth(width_hint, sign_hint); - while (children[0]->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param)) { } + while (children[0]->simplify(const_fold, stage, width_hint, sign_hint)) { } 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); @@ -1695,7 +1689,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi goto keep_const_cond; if (v->type == AST_BLOCK) continue; - while (v->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param)) { } + while (v->simplify(const_fold, stage, width_hint, sign_hint)) { } if (v->type == AST_CONSTANT && v->bits_only_01()) { RTLIL::Const case_item_expr = v->bitsAsConst(width_hint, sign_hint); RTLIL::Const match = const_eq(case_expr, case_item_expr, sign_hint, sign_hint, 1); @@ -1752,20 +1746,18 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi unevaluated_tern_branch = chosen && chosen != children[i]; } while (did_something_here && i < children.size()) { - bool const_fold_here = const_fold, in_lvalue_here = in_lvalue; + bool const_fold_here = const_fold; int width_hint_here = width_hint; bool sign_hint_here = sign_hint; bool in_param_here = in_param; if (i == 0 && (type == AST_REPLICATE || type == AST_WIRE)) - const_fold_here = true, in_param_here = true; + const_fold_here = true; if (i == 0 && (type == AST_GENIF || type == AST_GENCASE)) in_param_here = true; if (i == 1 && (type == AST_FOR || type == AST_GENFOR)) in_param_here = true; if (type == AST_PARAMETER || type == AST_LOCALPARAM) const_fold_here = true; - if (i == 0 && (type == AST_ASSIGN || type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE)) - in_lvalue_here = true; if (type == AST_BLOCK) { current_block = this; current_block_child = children[i]; @@ -1780,7 +1772,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi width_hint_here = -1, sign_hint_here = false; if (children_are_self_determined) width_hint_here = -1, sign_hint_here = false; - did_something_here = children[i]->simplify(const_fold_here, in_lvalue_here, stage, width_hint_here, sign_hint_here, in_param_here); + did_something_here = children[i]->simplify(const_fold_here, stage, width_hint_here, sign_hint_here); if (did_something_here) did_something = true; } @@ -1800,7 +1792,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi } } for (auto &attr : attributes) { - while (attr.second->simplify(true, false, stage, -1, false, true)) + while (attr.second->simplify(true, stage, -1, false)) did_something = true; } if (type == AST_CASE && stage == 2) { @@ -1878,7 +1870,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi log_assert(children.size() == 1); 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, in_lvalue, stage, width_hint, sign_hint, in_param)) { + while (type_node->simplify(const_fold, stage, width_hint, sign_hint)) { did_something = true; } log_assert(!type_node->is_custom_type); @@ -1900,7 +1892,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi AstNode *template_node = resolved_type_node->children[0]; // Ensure typedef itself is fully simplified - while (template_node->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, false)) {}; + while (template_node->simplify(const_fold, stage, width_hint, sign_hint)) {}; if (!str.empty() && str[0] == '\\' && (template_node->type == AST_STRUCT || template_node->type == AST_UNION)) { // replace instance with wire representing the packed structure @@ -1966,7 +1958,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi AstNode *template_node = resolved_type_node->children[0]; // Ensure typedef itself is fully simplified - while (template_node->simplify(const_fold, false, stage, width_hint, sign_hint, false)) {}; + while (template_node->simplify(const_fold, stage, width_hint, sign_hint)) {}; if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) { // replace with wire representing the packed structure @@ -2009,7 +2001,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi input_error("Index in generate block prefix syntax is not constant!\n"); } if (children[1]->type == AST_PREFIX) - children[1]->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param); + children[1]->simplify(const_fold, stage, width_hint, sign_hint); log_assert(children[1]->type == AST_IDENTIFIER); newNode = children[1]->clone(); const char *second_part = children[1]->str.c_str(); @@ -2304,7 +2296,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (current_block) wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); current_ast_mod->children.push_back(wire); - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } AstNode *data = clone(); delete data->children[1]; @@ -2346,7 +2338,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi AstNode *body = children[1]; // eval count expression - while (count->simplify(true, false, stage, 32, true, false)) { } + while (count->simplify(true, stage, 32, true)) { } if (count->type != AST_CONSTANT) input_error("Repeat loops outside must have constant repeat counts!\n"); @@ -2402,7 +2394,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi int expr_width_hint = -1; bool expr_sign_hint = true; varbuf->detectSignWidth(expr_width_hint, expr_sign_hint); - while (varbuf->simplify(true, false, stage, 32, true, false)) { } + while (varbuf->simplify(true, stage, 32, true)) { } } if (varbuf->type != AST_CONSTANT) @@ -2443,7 +2435,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi int expr_width_hint = -1; bool expr_sign_hint = true; buf->detectSignWidth(expr_width_hint, expr_sign_hint); - while (buf->simplify(true, false, stage, expr_width_hint, expr_sign_hint, false)) { } + while (buf->simplify(true, stage, expr_width_hint, expr_sign_hint)) { } } if (buf->type != AST_CONSTANT) @@ -2478,7 +2470,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (type == AST_GENFOR) { for (size_t i = 0; i < buf->children.size(); i++) { - buf->children[i]->simplify(const_fold, false, stage, -1, false, false); + buf->children[i]->simplify(const_fold, stage, -1, false); current_ast_mod->children.push_back(buf->children[i]); } } else { @@ -2495,7 +2487,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi int expr_width_hint = -1; bool expr_sign_hint = true; buf->detectSignWidth(expr_width_hint, expr_sign_hint); - while (buf->simplify(true, false, stage, expr_width_hint, expr_sign_hint, true)) { } + while (buf->simplify(true, stage, expr_width_hint, expr_sign_hint)) { } } if (buf->type != AST_CONSTANT) @@ -2547,7 +2539,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi 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, false, stage, -1, false, false); + children[i]->simplify(false, stage, -1, false); current_ast_mod->children.push_back(children[i]); current_scope[children[i]->str] = children[i]; } else @@ -2566,7 +2558,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi } for (size_t i = 0; i < children.size(); i++) { - children[i]->simplify(const_fold, false, stage, -1, false, false); + children[i]->simplify(const_fold, stage, -1, false); current_ast_mod->children.push_back(children[i]); } @@ -2578,7 +2570,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (type == AST_GENIF && children.size() != 0) { AstNode *buf = children[0]->clone(); - while (buf->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) { // for (auto f : log_files) // dumpAst(f, "verilog-ast> "); @@ -2602,7 +2594,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi } for (size_t i = 0; i < buf->children.size(); i++) { - buf->children[i]->simplify(const_fold, false, stage, -1, false, false); + buf->children[i]->simplify(const_fold, stage, -1, false); current_ast_mod->children.push_back(buf->children[i]); } @@ -2618,7 +2610,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (type == AST_GENCASE && children.size() != 0) { AstNode *buf = children[0]->clone(); - while (buf->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) { // for (auto f : log_files) // dumpAst(f, "verilog-ast> "); @@ -2653,7 +2645,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi buf = child->clone(); buf->set_in_param_flag(true); - while (buf->simplify(true, false, stage, width_hint, sign_hint, true)) { } + while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) { // for (auto f : log_files) // dumpAst(f, "verilog-ast> "); @@ -2681,7 +2673,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi } for (size_t i = 0; i < buf->children.size(); i++) { - buf->children[i]->simplify(const_fold, false, stage, -1, false, false); + buf->children[i]->simplify(const_fold, stage, -1, false); current_ast_mod->children.push_back(buf->children[i]); } @@ -2866,7 +2858,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (children[0]->id2ast->attributes.count(ID::nowrshmsk)) { AstNode *node = children[0]->id2ast->attributes.at(ID::nowrshmsk); - while (node->simplify(true, false, stage, -1, false, true)) { } + while (node->simplify(true, stage, -1, false)) { } if (node->type != AST_CONSTANT) input_error("Non-constant value for `nowrshmsk' attribute on `%s'!\n", children[0]->id2ast->str.c_str()); if (node->asAttrConst().as_bool()) @@ -2904,14 +2896,14 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); wire_mask->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire_mask->is_logic = true; - while (wire_mask->simplify(true, false, 1, -1, false, false)) { } + while (wire_mask->simplify(true, 1, -1, false)) { } current_ast_mod->children.push_back(wire_mask); AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire_data->is_logic = true; - while (wire_data->simplify(true, false, 1, -1, false, false)) { } + while (wire_data->simplify(true, 1, -1, false)) { } current_ast_mod->children.push_back(wire_data); int shamt_width_hint = -1; @@ -2923,7 +2915,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi wire_sel->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire_sel->is_logic = true; wire_sel->is_signed = shamt_sign_hint; - while (wire_sel->simplify(true, false, 1, -1, false, false)) { } + while (wire_sel->simplify(true, 1, -1, false)) { } current_ast_mod->children.push_back(wire_sel); did_something = true; @@ -3008,7 +3000,7 @@ skip_dynamic_range_lvalue_expansion:; wire_check->was_checked = true; current_ast_mod->children.push_back(wire_check); current_scope[wire_check->str] = wire_check; - while (wire_check->simplify(true, false, 1, -1, false, false)) { } + while (wire_check->simplify(true, 1, -1, false)) { } AstNode *wire_en = new AstNode(AST_WIRE); wire_en->str = id_en; @@ -3020,7 +3012,7 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.back()->children[0]->children[0]->children[0]->was_checked = true; } current_scope[wire_en->str] = wire_en; - while (wire_en->simplify(true, false, 1, -1, false, false)) { } + while (wire_en->simplify(true, 1, -1, false)) { } AstNode *check_defval; if (type == AST_LIVE || type == AST_FAIR) { @@ -3116,7 +3108,7 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(wire_tmp); current_scope[wire_tmp->str] = wire_tmp; wire_tmp->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); - while (wire_tmp->simplify(true, false, 1, -1, false, false)) { } + while (wire_tmp->simplify(true, 1, -1, false)) { } wire_tmp->is_logic = true; AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER); @@ -3186,7 +3178,7 @@ skip_dynamic_range_lvalue_expansion:; wire_addr->was_checked = true; current_ast_mod->children.push_back(wire_addr); current_scope[wire_addr->str] = wire_addr; - while (wire_addr->simplify(true, false, 1, -1, false, false)) { } + 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)); assign_addr->children[0]->str = id_addr; @@ -3212,7 +3204,7 @@ skip_dynamic_range_lvalue_expansion:; wire_data->is_signed = mem_signed; current_ast_mod->children.push_back(wire_data); current_scope[wire_data->str] = wire_data; - while (wire_data->simplify(true, false, 1, -1, false, false)) { } + 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)); assign_data->children[0]->str = id_data; @@ -3228,7 +3220,7 @@ skip_dynamic_range_lvalue_expansion:; wire_en->was_checked = true; current_ast_mod->children.push_back(wire_en); current_scope[wire_en->str] = wire_en; - while (wire_en->simplify(true, false, 1, -1, false, false)) { } + 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)); assign_en_first->children[0]->str = id_en; @@ -3356,7 +3348,7 @@ skip_dynamic_range_lvalue_expansion:; AstNode *wire = new AstNode(AST_WIRE); wire->str = stringf("$initstate$%d_wire", myidx); current_ast_mod->children.push_back(wire); - while (wire->simplify(true, false, 1, -1, false, false)) { } + 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))); cell->str = stringf("$initstate$%d", myidx); @@ -3365,7 +3357,7 @@ skip_dynamic_range_lvalue_expansion:; cell->children[1]->children[0]->str = wire->str; cell->children[1]->children[0]->id2ast = wire; current_ast_mod->children.push_back(cell); - while (cell->simplify(true, false, 1, -1, false, false)) { } + while (cell->simplify(true, 1, -1, false)) { } newNode = new AstNode(AST_IDENTIFIER); newNode->str = wire->str; @@ -3391,7 +3383,7 @@ skip_dynamic_range_lvalue_expansion:; if (GetSize(children) == 2) { AstNode *buf = children[1]->clone(); - while (buf->simplify(true, false, stage, -1, false, false)) { } + 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()); @@ -3426,7 +3418,7 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(reg); - while (reg->simplify(true, false, 1, -1, false, false)) { } + while (reg->simplify(true, 1, -1, false)) { } AstNode *regid = new AstNode(AST_IDENTIFIER); regid->str = reg->str; @@ -3502,7 +3494,7 @@ skip_dynamic_range_lvalue_expansion:; RTLIL::unescape_id(str).c_str(), int(children.size())); AstNode *buf = children[0]->clone(); - while (buf->simplify(true, false, stage, width_hint, sign_hint, false)) { } + 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()); @@ -3534,7 +3526,7 @@ skip_dynamic_range_lvalue_expansion:; if (children.size() == 2) { AstNode *buf = children[1]->clone(); // Evaluate constant expression - while (buf->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (buf->simplify(true, stage, width_hint, sign_hint)) { } dim = buf->asInt(false); delete buf; } @@ -3692,7 +3684,7 @@ skip_dynamic_range_lvalue_expansion:; } if (children.size() >= 1) { - while (children[0]->simplify(true, false, stage, width_hint, sign_hint, in_param)) { } + while (children[0]->simplify(true, stage, width_hint, sign_hint)) { } if (!children[0]->isConst()) input_error("Failed to evaluate system function `%s' with non-constant argument.\n", RTLIL::unescape_id(str).c_str()); @@ -3703,7 +3695,7 @@ skip_dynamic_range_lvalue_expansion:; } if (children.size() >= 2) { - while (children[1]->simplify(true, false, stage, width_hint, sign_hint, in_param)) { } + while (children[1]->simplify(true, stage, width_hint, sign_hint)) { } if (!children[1]->isConst()) input_error("Failed to evaluate system function `%s' with non-constant argument.\n", RTLIL::unescape_id(str).c_str()); @@ -3760,7 +3752,7 @@ skip_dynamic_range_lvalue_expansion:; // Determine which bits to count for (size_t i = 1; i < children.size(); i++) { AstNode *node = children[i]; - while (node->simplify(true, false, stage, -1, false, in_param)) { } + 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()); if (node->bits.size() != 1) @@ -3855,8 +3847,7 @@ skip_dynamic_range_lvalue_expansion:; argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str)); args.push_back(children.at(i-2)->clone()); - args.back()->set_in_param_flag(true); - while (args.back()->simplify(true, false, stage, -1, false, true)) { } + while (args.back()->simplify(true, stage, -1, false)) { } if (args.back()->type != AST_CONSTANT && args.back()->type != AST_REALVALUE) input_error("Failed to evaluate DPI function with non-constant argument.\n"); @@ -3893,12 +3884,12 @@ skip_dynamic_range_lvalue_expansion:; RTLIL::unescape_id(str).c_str(), int(children.size())); AstNode *node_filename = children[0]->clone(); - while (node_filename->simplify(true, false, stage, width_hint, sign_hint, false)) { } + 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(); - while (node_memory->simplify(true, false, stage, width_hint, sign_hint, false)) { } + 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()); @@ -3906,7 +3897,7 @@ skip_dynamic_range_lvalue_expansion:; if (GetSize(children) > 2) { AstNode *node_addr = children[2]->clone(); - while (node_addr->simplify(true, false, stage, width_hint, sign_hint, false)) { } + 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()); start_addr = int(node_addr->asInt(false)); @@ -3914,7 +3905,7 @@ skip_dynamic_range_lvalue_expansion:; if (GetSize(children) > 3) { AstNode *node_addr = children[3]->clone(); - while (node_addr->simplify(true, false, stage, width_hint, sign_hint, false)) { } + 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()); finish_addr = int(node_addr->asInt(false)); @@ -3966,7 +3957,7 @@ skip_dynamic_range_lvalue_expansion:; bool require_const_eval = decl->has_const_only_constructs(); bool all_args_const = true; for (auto child : children) { - while (child->simplify(true, in_lvalue, 1, -1, false, in_param)) { } + while (child->simplify(true, 1, -1, false)) { } if (child->type != AST_CONSTANT && child->type != AST_REALVALUE) all_args_const = false; } @@ -4011,7 +4002,7 @@ skip_dynamic_range_lvalue_expansion:; current_scope[wire->str] = wire; current_ast_mod->children.push_back(wire); - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } AstNode *lvalue = new AstNode(AST_IDENTIFIER); lvalue->str = wire->str; @@ -4057,7 +4048,7 @@ skip_dynamic_range_lvalue_expansion:; wire->is_input = false; wire->is_output = false; current_ast_mod->children.push_back(wire); - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } AstNode *wire_id = new AstNode(AST_IDENTIFIER); wire_id->str = wire->str; @@ -4100,7 +4091,7 @@ skip_dynamic_range_lvalue_expansion:; for (auto c : child->children) wire->children.push_back(c->clone()); } else if (!child->children.empty()) { - while (child->simplify(true, false, stage, -1, false, false)) { } + while (child->simplify(true, stage, -1, false)) { } if (GetSize(child->children) == GetSize(wire->children) - contains_value) { for (int i = 0; i < GetSize(child->children); i++) if (*child->children.at(i) != *wire->children.at(i + contains_value)) @@ -4128,7 +4119,7 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(wire); } - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } if ((child->is_input || child->is_output) && arg_count < children.size()) { @@ -4161,7 +4152,7 @@ skip_dynamic_range_lvalue_expansion:; } wire->fixup_hierarchy_flags(); // updates the sizing - while (wire->simplify(true, false, 1, -1, false, true)) { } + while (wire->simplify(true, 1, -1, false)) { } delete arg; continue; } @@ -5072,7 +5063,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, 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, false, 1, -1, false, false)) { } + while (wire_addr->simplify(true, 1, -1, false)) { } AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_data->str = id_data; @@ -5081,7 +5072,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, 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, false, 1, -1, false, false)) { } + while (wire_data->simplify(true, 1, -1, false)) { } log_assert(block != NULL); size_t assign_idx = 0; @@ -5194,7 +5185,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, if (block) wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_addr); - while (wire_addr->simplify(true, false, 1, -1, false, false)) { } + while (wire_addr->simplify(true, 1, -1, false)) { } AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_data->str = id_data; @@ -5204,7 +5195,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, if (block) wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_data); - while (wire_data->simplify(true, false, 1, -1, false, false)) { } + while (wire_data->simplify(true, 1, -1, false)) { } AstNode *assign_addr = new AstNode(block ? AST_ASSIGN_EQ : AST_ASSIGN, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; @@ -5387,7 +5378,7 @@ bool AstNode::replace_variables(std::map &varia } if (!children.at(0)->replace_variables(variables, fcall, must_succeed)) return false; - while (simplify(true, false, 1, -1, false, true)) { } + while (simplify(true, 1, -1, false)) { } if (!children.at(0)->range_valid) { if (!must_succeed) return false; @@ -5443,7 +5434,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) if (stmt->type == AST_WIRE) { - while (stmt->simplify(true, false, 1, -1, false, true)) { } + while (stmt->simplify(true, 1, -1, false)) { } if (!stmt->range_valid) { if (!must_succeed) goto finished; @@ -5487,7 +5478,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) if (stmt->type == AST_LOCALPARAM) { - while (stmt->simplify(true, false, 1, -1, false, true)) { } + while (stmt->simplify(true, 1, -1, false)) { } current_scope[stmt->str] = stmt; @@ -5504,7 +5495,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) goto finished; if (!stmt->children.at(1)->replace_variables(variables, fcall, must_succeed)) goto finished; - while (stmt->simplify(true, false, 1, -1, false, true)) { } + while (stmt->simplify(true, 1, -1, false)) { } if (stmt->type != AST_ASSIGN_EQ) continue; @@ -5572,7 +5563,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) if (!cond->replace_variables(variables, fcall, must_succeed)) goto finished; cond->set_in_param_flag(true); - while (cond->simplify(true, false, 1, -1, false, true)) { } + while (cond->simplify(true, 1, -1, false)) { } if (cond->type != AST_CONSTANT) { if (!must_succeed) @@ -5598,7 +5589,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) if (!num->replace_variables(variables, fcall, must_succeed)) goto finished; num->set_in_param_flag(true); - while (num->simplify(true, false, 1, -1, false, true)) { } + while (num->simplify(true, 1, -1, false)) { } if (num->type != AST_CONSTANT) { if (!must_succeed) @@ -5622,7 +5613,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) if (!expr->replace_variables(variables, fcall, must_succeed)) goto finished; expr->set_in_param_flag(true); - while (expr->simplify(true, false, 1, -1, false, true)) { } + while (expr->simplify(true, 1, -1, false)) { } AstNode *sel_case = NULL; for (size_t i = 1; i < stmt->children.size(); i++) @@ -5643,7 +5634,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) cond = new AstNode(AST_EQ, expr->clone(), cond); cond->set_in_param_flag(true); - while (cond->simplify(true, false, 1, -1, false, true)) { } + while (cond->simplify(true, 1, -1, false)) { } if (cond->type != AST_CONSTANT) { if (!must_succeed) From c172fef01a23deee96a3b1bf45bdfd7b993376bf Mon Sep 17 00:00:00 2001 From: Wanda Date: Tue, 26 Sep 2023 18:56:54 +0200 Subject: [PATCH 072/173] hashlib: Use a better hash for pool. --- kernel/hashlib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index b3f99bf730f..be759fdf0a4 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -988,7 +988,7 @@ class pool return !operator==(other); } - bool hash() const { + unsigned int hash() const { unsigned int hashval = mkhash_init; for (auto &it : entries) hashval ^= ops.hash(it.udata); From 076c5ceb714bc8f20136a83cc9818b96e6a542b4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 27 Sep 2023 00:15:07 +0000 Subject: [PATCH 073/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 77f7b80fadf..1fb47fa07d8 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+65 +YOSYS_VER := 0.33+67 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From f193ebdded593c837e9f3447fddf803723f8e5f9 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 27 Sep 2023 16:57:18 +0200 Subject: [PATCH 074/173] Verific: add default parameters to modules --- frontends/verific/verific.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index cd844dceeee..310e3918015 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1275,9 +1275,16 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma log("Importing module %s.\n", RTLIL::id2cstr(module->name)); } import_attributes(module->attributes, nl, nl); + const char *param_name ; + const char *param_value ; + MapIter mi; + FOREACH_PARAMETER_OF_NETLIST(nl, mi, param_name, param_value) { + module->avail_parameters(RTLIL::escape_id(param_name)); + module->parameter_default_values[RTLIL::escape_id(param_name)] = verific_const(param_value); + } SetIter si; - MapIter mi, mi2; + MapIter mi2; Port *port; PortBus *portbus; Net *net; From ac8b31e000cdcc68c2017070679821d4333f801e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 28 Sep 2023 00:15:01 +0000 Subject: [PATCH 075/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1fb47fa07d8..24184e8296e 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+67 +YOSYS_VER := 0.33+72 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 01a015747e274480fc5ae8d0fab18d89d04ea8b0 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Wed, 27 Sep 2023 17:16:13 -0700 Subject: [PATCH 076/173] Speed up RTLIL::Const::decode_string by 1.7x. --- kernel/rtlil.cc | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 1b57af60acb..3663ca864e0 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -313,18 +313,33 @@ RTLIL::Const RTLIL::Const::from_string(const std::string &str) std::string RTLIL::Const::decode_string() const { - std::string string; - string.reserve(GetSize(bits)/8); - for (int i = 0; i < GetSize(bits); i += 8) { + const int n = GetSize(bits); + const int n_over_8 = n / 8; + std::string s; + s.reserve(n_over_8); + int i = n_over_8 * 8; + if (i < n) { char ch = 0; - for (int j = 0; j < 8 && i + j < int (bits.size()); j++) - if (bits[i + j] == RTLIL::State::S1) + for (int j = 0; j < (n - i); j++) { + if (bits[j + i] == RTLIL::State::S1) { ch |= 1 << j; + } + } + if (ch != 0) + s.append({ch}); + } + i -= 8; + for (; i >= 0; i -= 8) { + char ch = 0; + for (int j = 0; j < 8; j++) { + if (bits[j + i] == RTLIL::State::S1) { + ch |= 1 << j; + } + } if (ch != 0) - string.append({ch}); + s.append({ch}); } - std::reverse(string.begin(), string.end()); - return string; + return s; } bool RTLIL::Const::is_fully_zero() const @@ -4044,7 +4059,7 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec other->bits_[j] = with.bits_[it->second]; } } - + other->check(); } From 6b70b3dbefea7972c44e312c356bf7377a7d5f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 28 Sep 2023 11:50:57 +0200 Subject: [PATCH 077/173] booth: Fix assertion Fix assertion to what it should be per Andy's comments. --- passes/techmap/booth.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index be38c8fc39f..000dcff14ec 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -655,8 +655,7 @@ struct BoothPassWorker { cpa_id++; log_assert(c_vec.size() == s_vec.size()); - // TODO: doesn't pass - //log_assert(result.size() == s_vec.size() + 2); + log_assert(result.size() == s_vec.size()); SigBit carry; for (int n = 0; n < s_vec.size(); n++) { From b0045300fd7ee6a123d3a3a373448e4780c3bcfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 28 Sep 2023 11:55:51 +0200 Subject: [PATCH 078/173] booth: Cut down the test Cut the test down from taking ~25 s to ~3 s. --- tests/techmap/booth.ys | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/techmap/booth.ys b/tests/techmap/booth.ys index f1dce1f3b27..ab7efc7b7fd 100644 --- a/tests/techmap/booth.ys +++ b/tests/techmap/booth.ys @@ -1 +1 @@ -test_cell -s 1694091355 -n 1000 -script booth_map_script.ys_ $mul +test_cell -s 1694091355 -n 100 -script booth_map_script.ys_ $mul From 7eaa4bcb4605d6c1d30d4daf96a94cea3b423df3 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Thu, 28 Sep 2023 17:29:24 +0200 Subject: [PATCH 079/173] sim: Add -noinitstate option and handle non-cosim initstate This adds the -noinitstate option which is required to simulate counterexamples to induction with yw-cosim. Also add handling for $initstate cells for non-co-simulation. --- passes/sat/sim.cc | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 1e6645303b5..963c6481b16 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -111,6 +111,7 @@ struct SimShared int step = 0; std::vector triggered_assertions; bool serious_asserts = false; + bool initstate = true; }; void zinit(State &v) @@ -1356,6 +1357,8 @@ struct SimWorker : SimShared set_inports(clock, State::Sx); set_inports(clockn, State::Sx); + top->set_initstate_outputs(initstate ? State::S1 : State::S0); + update(false); register_output_step(0); @@ -1372,6 +1375,9 @@ struct SimWorker : SimShared update(true); register_output_step(10*cycle + 5); + if (cycle == 0) + top->set_initstate_outputs(State::S0); + if (debug) log("\n===== %d =====\n", 10*cycle + 10); else if (verbose) @@ -1953,7 +1959,7 @@ struct SimWorker : SimShared if (yw.steps.empty()) { log_warning("Yosys witness file `%s` contains no time steps\n", yw.filename.c_str()); } else { - top->set_initstate_outputs(State::S1); + top->set_initstate_outputs(initstate ? State::S1 : State::S0); set_yw_state(yw, hierarchy, 0); set_yw_clocks(yw, hierarchy, true); initialize_stable_past(); @@ -2546,6 +2552,9 @@ struct SimPass : public Pass { log(" -n \n"); log(" number of clock cycles to simulate (default: 20)\n"); log("\n"); + log(" -noinitstate\n"); + log(" do not activate $initstate cells during the first cycle\n"); + log("\n"); log(" -a\n"); log(" use all nets in VCD/FST operations, not just those with public names\n"); log("\n"); @@ -2646,6 +2655,10 @@ struct SimPass : public Pass { worker.cycles_set = true; continue; } + if (args[argidx] == "-noinitstate") { + worker.initstate = false; + continue; + } if (args[argidx] == "-rstlen" && argidx+1 < args.size()) { worker.rstlen = atoi(args[++argidx].c_str()); continue; From 5daa49bafbcb40816e9a56f249568127d275c59d Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Thu, 28 Sep 2023 17:32:19 +0200 Subject: [PATCH 080/173] dft_tag: Fix size extending $x[n]or and $reduce_{or,bool}/$logic_not --- passes/cmds/dft_tag.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/passes/cmds/dft_tag.cc b/passes/cmds/dft_tag.cc index 9fd356ef65d..2b2340dab53 100644 --- a/passes/cmds/dft_tag.cc +++ b/passes/cmds/dft_tag.cc @@ -405,7 +405,7 @@ struct DftTagWorker { auto &sig_y = cell->getPort(ID::Y); auto sig_a = cell->getPort(ID::A); auto sig_b = cell->getPort(ID::B); - if (cell->type.in(ID($and), ID($or))) { + if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor))) { sig_a.extend_u0(GetSize(sig_y), cell->getParam(ID::A_SIGNED).as_bool()); sig_b.extend_u0(GetSize(sig_y), cell->getParam(ID::B_SIGNED).as_bool()); } @@ -669,12 +669,12 @@ struct DftTagWorker { auto &sig_y = cell->getPort(ID::Y); auto sig_a = cell->getPort(ID::A); - if (cell->type.in(ID($reduce_or), ID($reduce_bool), ID($logic_not))) - sig_a = autoNot(NEW_ID, sig_a); - auto group_sig_a = tag_group_signal(tag, sig_a); auto tag_sig_a = tag_signal(tag, sig_a); + if (cell->type.in(ID($reduce_or), ID($reduce_bool), ID($logic_not))) + sig_a = autoNot(NEW_ID, sig_a); + auto filled = autoOr(NEW_ID, sig_a, group_sig_a); auto prop = autoReduceAnd(NEW_ID, filled); From 12218a4c744cb3877e5d9e78d15b7c2d90667907 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Thu, 28 Sep 2023 19:39:09 -0700 Subject: [PATCH 081/173] Unflip i and j. --- kernel/rtlil.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 3663ca864e0..9834a0d37af 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -321,7 +321,7 @@ std::string RTLIL::Const::decode_string() const if (i < n) { char ch = 0; for (int j = 0; j < (n - i); j++) { - if (bits[j + i] == RTLIL::State::S1) { + if (bits[i + j] == RTLIL::State::S1) { ch |= 1 << j; } } @@ -332,7 +332,7 @@ std::string RTLIL::Const::decode_string() const for (; i >= 0; i -= 8) { char ch = 0; for (int j = 0; j < 8; j++) { - if (bits[j + i] == RTLIL::State::S1) { + if (bits[i + j] == RTLIL::State::S1) { ch |= 1 << j; } } From cc843d414f7a68c0140c0bc038b937210650ba78 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Fri, 29 Sep 2023 12:28:50 +0200 Subject: [PATCH 082/173] simplify: Avoid calling fixup_hierarchy_flags on nullptr Compiling on GCC hid this bug as it optimized the nullptr call away as undefined behavior, but running the SBY tests with a clang build hits this error. --- frontends/ast/simplify.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index c4a30302712..c5f0467041d 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -3042,8 +3042,8 @@ skip_dynamic_range_lvalue_expansion:; assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone())); assign_check->children[0]->str = id_check; assign_check->children[0]->was_checked = true; + assign_check->fixup_hierarchy_flags(); } - assign_check->fixup_hierarchy_flags(); if (current_always == nullptr || current_always->type != AST_INITIAL) { assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1)); From b52f6cb1991b7117d23fa119bf808f9fc1849789 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 30 Sep 2023 00:14:39 +0000 Subject: [PATCH 083/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 24184e8296e..a96f3f54919 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+72 +YOSYS_VER := 0.33+79 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 98d2c9088acfc1da368e36f15bc5d40a61718079 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Fri, 29 Sep 2023 13:26:22 -0700 Subject: [PATCH 084/173] Ignore emacs auto-save files. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 49b886e7e43..9b799c1f38d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.gch *.gcda *.gcno +*~ __pycache__ /.cproject /.project From abd9c519634f5279cb7f85a6884d47d23a8583e4 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Fri, 29 Sep 2023 10:53:37 -0700 Subject: [PATCH 085/173] Speed up simplemap_map by 11.6x by directly inserting the cell source attribute in the new object's 'attributes' map instead of calling set_attr_pool to create a new pool and then copying that. Based on a suggestion by Martin Poviser in a comment on https://github.com/YosysHQ/yosys/pull/3959 --- passes/techmap/simplemap.cc | 228 ++++++++++++++++-------------- passes/techmap/techmap.cc | 274 +++++++++++++++++------------------- 2 files changed, 252 insertions(+), 250 deletions(-) diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index 11692b715ea..14c07922b14 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -18,10 +18,10 @@ */ #include "simplemap.h" -#include "kernel/sigtools.h" #include "kernel/ff.h" -#include +#include "kernel/sigtools.h" #include +#include #include USING_YOSYS_NAMESPACE @@ -36,7 +36,7 @@ void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); gate->setPort(ID::Y, sig_y[i]); } @@ -64,16 +64,21 @@ void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell) } IdString gate_type; - if (cell->type == ID($and)) gate_type = ID($_AND_); - if (cell->type == ID($or)) gate_type = ID($_OR_); - if (cell->type == ID($xor)) gate_type = ID($_XOR_); - if (cell->type == ID($xnor)) gate_type = ID($_XNOR_); - if (cell->type == ID($bweqx)) gate_type = ID($_XNOR_); + if (cell->type == ID($and)) + gate_type = ID($_AND_); + if (cell->type == ID($or)) + gate_type = ID($_OR_); + if (cell->type == ID($xor)) + gate_type = ID($_XOR_); + if (cell->type == ID($xnor)) + gate_type = ID($_XNOR_); + if (cell->type == ID($bweqx)) + gate_type = ID($_XNOR_); log_assert(!gate_type.empty()); for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); gate->setPort(ID::B, sig_b[i]); gate->setPort(ID::Y, sig_y[i]); @@ -89,45 +94,53 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) return; if (sig_a.size() == 0) { - if (cell->type == ID($reduce_and)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); - if (cell->type == ID($reduce_or)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); - if (cell->type == ID($reduce_xor)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); - if (cell->type == ID($reduce_xnor)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); - if (cell->type == ID($reduce_bool)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == ID($reduce_and)) + module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); + if (cell->type == ID($reduce_or)) + module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == ID($reduce_xor)) + module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == ID($reduce_xnor)) + module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); + if (cell->type == ID($reduce_bool)) + module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); return; } if (sig_y.size() > 1) { - module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size() - 1), RTLIL::SigSpec(0, sig_y.size() - 1))); sig_y = sig_y.extract(0, 1); } IdString gate_type; - if (cell->type == ID($reduce_and)) gate_type = ID($_AND_); - if (cell->type == ID($reduce_or)) gate_type = ID($_OR_); - if (cell->type == ID($reduce_xor)) gate_type = ID($_XOR_); - if (cell->type == ID($reduce_xnor)) gate_type = ID($_XOR_); - if (cell->type == ID($reduce_bool)) gate_type = ID($_OR_); + if (cell->type == ID($reduce_and)) + gate_type = ID($_AND_); + if (cell->type == ID($reduce_or)) + gate_type = ID($_OR_); + if (cell->type == ID($reduce_xor)) + gate_type = ID($_XOR_); + if (cell->type == ID($reduce_xnor)) + gate_type = ID($_XOR_); + if (cell->type == ID($reduce_bool)) + gate_type = ID($_OR_); log_assert(!gate_type.empty()); RTLIL::Cell *last_output_cell = NULL; - while (sig_a.size() > 1) - { + while (sig_a.size() > 1) { RTLIL::SigSpec sig_t = module->addWire(NEW_ID, sig_a.size() / 2); - for (int i = 0; i < sig_a.size(); i += 2) - { - if (i+1 == sig_a.size()) { + for (int i = 0; i < sig_a.size(); i += 2) { + if (i + 1 == sig_a.size()) { sig_t.append(sig_a[i]); continue; } RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); - gate->setPort(ID::B, sig_a[i+1]); - gate->setPort(ID::Y, sig_t[i/2]); + gate->setPort(ID::B, sig_a[i + 1]); + gate->setPort(ID::Y, sig_t[i / 2]); last_output_cell = gate; } @@ -137,7 +150,7 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) if (cell->type == ID($reduce_xnor)) { RTLIL::SigSpec sig_t = module->addWire(NEW_ID); RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a); gate->setPort(ID::Y, sig_t); last_output_cell = gate; @@ -153,22 +166,20 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLIL::Cell *cell) { - while (sig.size() > 1) - { + while (sig.size() > 1) { RTLIL::SigSpec sig_t = module->addWire(NEW_ID, sig.size() / 2); - for (int i = 0; i < sig.size(); i += 2) - { - if (i+1 == sig.size()) { + for (int i = 0; i < sig.size(); i += 2) { + if (i + 1 == sig.size()) { sig_t.append(sig[i]); continue; } RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_OR_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig[i]); - gate->setPort(ID::B, sig[i+1]); - gate->setPort(ID::Y, sig_t[i/2]); + gate->setPort(ID::B, sig[i + 1]); + gate->setPort(ID::Y, sig_t[i / 2]); } sig = sig_t; @@ -189,12 +200,12 @@ void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell) return; if (sig_y.size() > 1) { - module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size() - 1), RTLIL::SigSpec(0, sig_y.size() - 1))); sig_y = sig_y.extract(0, 1); } RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a); gate->setPort(ID::Y, sig_y); } @@ -213,17 +224,19 @@ void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell) return; if (sig_y.size() > 1) { - module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size() - 1), RTLIL::SigSpec(0, sig_y.size() - 1))); sig_y = sig_y.extract(0, 1); } IdString gate_type; - if (cell->type == ID($logic_and)) gate_type = ID($_AND_); - if (cell->type == ID($logic_or)) gate_type = ID($_OR_); + if (cell->type == ID($logic_and)) + gate_type = ID($_AND_); + if (cell->type == ID($logic_or)) + gate_type = ID($_OR_); log_assert(!gate_type.empty()); RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a); gate->setPort(ID::B, sig_b); gate->setPort(ID::Y, sig_y); @@ -239,19 +252,22 @@ void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell) RTLIL::SigSpec xor_out = module->addWire(NEW_ID, max(GetSize(sig_a), GetSize(sig_b))); RTLIL::Cell *xor_cell = module->addXor(NEW_ID, sig_a, sig_b, xor_out, is_signed); - xor_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + xor_cell->attributes[ID::src] = cell->attributes[ID::src]; + // xor_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); simplemap_bitop(module, xor_cell); module->remove(xor_cell); RTLIL::SigSpec reduce_out = is_ne ? sig_y : module->addWire(NEW_ID); RTLIL::Cell *reduce_cell = module->addReduceOr(NEW_ID, xor_out, reduce_out); - reduce_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + reduce_cell->attributes[ID::src] = cell->attributes[ID::src]; + // reduce_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); simplemap_reduce(module, reduce_cell); module->remove(reduce_cell); if (!is_ne) { RTLIL::Cell *not_cell = module->addLogicNot(NEW_ID, reduce_out, sig_y); - not_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + not_cell->attributes[ID::src] = cell->attributes[ID::src]; + // not_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); simplemap_lognot(module, not_cell); module->remove(not_cell); } @@ -265,7 +281,7 @@ void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); gate->setPort(ID::B, sig_b[i]); gate->setPort(ID::S, cell->getPort(ID::S)); @@ -282,7 +298,7 @@ void simplemap_bwmux(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); gate->setPort(ID::B, sig_b[i]); gate->setPort(ID::S, sig_s[i]); @@ -298,7 +314,7 @@ void simplemap_tribuf(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_TBUF_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); gate->setPort(ID::E, sig_e); gate->setPort(ID::Y, sig_y[i]); @@ -312,15 +328,15 @@ void simplemap_bmux(RTLIL::Module *module, RTLIL::Cell *cell) int width = GetSize(cell->getPort(ID::Y)); for (int idx = 0; idx < GetSize(sel); idx++) { - SigSpec new_data = module->addWire(NEW_ID, GetSize(data)/2); + SigSpec new_data = module->addWire(NEW_ID, GetSize(data) / 2); for (int i = 0; i < GetSize(new_data); i += width) { for (int k = 0; k < width; k++) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - gate->setPort(ID::A, data[i*2+k]); - gate->setPort(ID::B, data[i*2+width+k]); + gate->attributes[ID::src] = cell->attributes[ID::src]; + gate->setPort(ID::A, data[i * 2 + k]); + gate->setPort(ID::B, data[i * 2 + width + k]); gate->setPort(ID::S, sel[idx]); - gate->setPort(ID::Y, new_data[i+k]); + gate->setPort(ID::Y, new_data[i + k]); } } data = new_data; @@ -336,14 +352,14 @@ void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell) lut_data.extend_u0(1 << cell->getParam(ID::WIDTH).as_int()); for (int idx = 0; GetSize(lut_data) > 1; idx++) { - SigSpec new_lut_data = module->addWire(NEW_ID, GetSize(lut_data)/2); + SigSpec new_lut_data = module->addWire(NEW_ID, GetSize(lut_data) / 2); for (int i = 0; i < GetSize(lut_data); i += 2) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, lut_data[i]); - gate->setPort(ID::B, lut_data[i+1]); + gate->setPort(ID::B, lut_data[i + 1]); gate->setPort(ID::S, lut_ctrl[idx]); - gate->setPort(ID::Y, new_lut_data[i/2]); + gate->setPort(ID::Y, new_lut_data[i / 2]); } lut_data = new_lut_data; } @@ -365,11 +381,11 @@ void simplemap_sop(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < depth; i++) { SigSpec in, pat; for (int j = 0; j < width; j++) { - if (table[2*i*width + 2*j + 0] == State::S1) { + if (table[2 * i * width + 2 * j + 0] == State::S1) { in.append(ctrl[j]); pat.append(State::S0); } - if (table[2*i*width + 2*j + 1] == State::S1) { + if (table[2 * i * width + 2 * j + 1] == State::S1) { in.append(ctrl[j]); pat.append(State::S1); } @@ -407,56 +423,56 @@ void simplemap_ff(RTLIL::Module *, RTLIL::Cell *cell) } } -void simplemap_get_mappers(dict &mappers) +void simplemap_get_mappers(dict &mappers) { - mappers[ID($not)] = simplemap_not; - mappers[ID($pos)] = simplemap_pos; - mappers[ID($and)] = simplemap_bitop; - mappers[ID($or)] = simplemap_bitop; - mappers[ID($xor)] = simplemap_bitop; - mappers[ID($xnor)] = simplemap_bitop; - mappers[ID($bweqx)] = simplemap_bitop; - mappers[ID($reduce_and)] = simplemap_reduce; - mappers[ID($reduce_or)] = simplemap_reduce; - mappers[ID($reduce_xor)] = simplemap_reduce; + mappers[ID($not)] = simplemap_not; + mappers[ID($pos)] = simplemap_pos; + mappers[ID($and)] = simplemap_bitop; + mappers[ID($or)] = simplemap_bitop; + mappers[ID($xor)] = simplemap_bitop; + mappers[ID($xnor)] = simplemap_bitop; + mappers[ID($bweqx)] = simplemap_bitop; + mappers[ID($reduce_and)] = simplemap_reduce; + mappers[ID($reduce_or)] = simplemap_reduce; + mappers[ID($reduce_xor)] = simplemap_reduce; mappers[ID($reduce_xnor)] = simplemap_reduce; mappers[ID($reduce_bool)] = simplemap_reduce; - mappers[ID($logic_not)] = simplemap_lognot; - mappers[ID($logic_and)] = simplemap_logbin; - mappers[ID($logic_or)] = simplemap_logbin; - mappers[ID($eq)] = simplemap_eqne; - mappers[ID($eqx)] = simplemap_eqne; - mappers[ID($ne)] = simplemap_eqne; - mappers[ID($nex)] = simplemap_eqne; - mappers[ID($mux)] = simplemap_mux; - mappers[ID($bwmux)] = simplemap_bwmux; - mappers[ID($tribuf)] = simplemap_tribuf; - mappers[ID($bmux)] = simplemap_bmux; - mappers[ID($lut)] = simplemap_lut; - mappers[ID($sop)] = simplemap_sop; - mappers[ID($slice)] = simplemap_slice; - mappers[ID($concat)] = simplemap_concat; - mappers[ID($sr)] = simplemap_ff; - mappers[ID($ff)] = simplemap_ff; - mappers[ID($dff)] = simplemap_ff; - mappers[ID($dffe)] = simplemap_ff; - mappers[ID($dffsr)] = simplemap_ff; - mappers[ID($dffsre)] = simplemap_ff; - mappers[ID($adff)] = simplemap_ff; - mappers[ID($sdff)] = simplemap_ff; - mappers[ID($adffe)] = simplemap_ff; - mappers[ID($sdffe)] = simplemap_ff; - mappers[ID($sdffce)] = simplemap_ff; - mappers[ID($aldff)] = simplemap_ff; - mappers[ID($aldffe)] = simplemap_ff; - mappers[ID($dlatch)] = simplemap_ff; - mappers[ID($adlatch)] = simplemap_ff; - mappers[ID($dlatchsr)] = simplemap_ff; + mappers[ID($logic_not)] = simplemap_lognot; + mappers[ID($logic_and)] = simplemap_logbin; + mappers[ID($logic_or)] = simplemap_logbin; + mappers[ID($eq)] = simplemap_eqne; + mappers[ID($eqx)] = simplemap_eqne; + mappers[ID($ne)] = simplemap_eqne; + mappers[ID($nex)] = simplemap_eqne; + mappers[ID($mux)] = simplemap_mux; + mappers[ID($bwmux)] = simplemap_bwmux; + mappers[ID($tribuf)] = simplemap_tribuf; + mappers[ID($bmux)] = simplemap_bmux; + mappers[ID($lut)] = simplemap_lut; + mappers[ID($sop)] = simplemap_sop; + mappers[ID($slice)] = simplemap_slice; + mappers[ID($concat)] = simplemap_concat; + mappers[ID($sr)] = simplemap_ff; + mappers[ID($ff)] = simplemap_ff; + mappers[ID($dff)] = simplemap_ff; + mappers[ID($dffe)] = simplemap_ff; + mappers[ID($dffsr)] = simplemap_ff; + mappers[ID($dffsre)] = simplemap_ff; + mappers[ID($adff)] = simplemap_ff; + mappers[ID($sdff)] = simplemap_ff; + mappers[ID($adffe)] = simplemap_ff; + mappers[ID($sdffe)] = simplemap_ff; + mappers[ID($sdffce)] = simplemap_ff; + mappers[ID($aldff)] = simplemap_ff; + mappers[ID($aldffe)] = simplemap_ff; + mappers[ID($dlatch)] = simplemap_ff; + mappers[ID($adlatch)] = simplemap_ff; + mappers[ID($dlatchsr)] = simplemap_ff; } void simplemap(RTLIL::Module *module, RTLIL::Cell *cell) { - static dict mappers; + static dict mappers; static bool initialized_mappers = false; if (!initialized_mappers) { @@ -471,7 +487,7 @@ YOSYS_NAMESPACE_END PRIVATE_NAMESPACE_BEGIN struct SimplemapPass : public Pass { - SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") { } + SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") {} void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -493,13 +509,13 @@ struct SimplemapPass : public Pass { log_header(design, "Executing SIMPLEMAP pass (map simple cells to gate primitives).\n"); extra_args(args, 1, design); - dict mappers; + dict mappers; simplemap_get_mappers(mappers); for (auto mod : design->modules()) { if (!design->selected(mod) || mod->get_blackbox_attribute()) continue; - std::vector cells = mod->cells(); + std::vector cells = mod->cells(); for (auto cell : cells) { if (mappers.count(cell->type) == 0) continue; diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 144f596c88c..52a24dcf3ba 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -17,14 +17,14 @@ * */ -#include "kernel/yosys.h" -#include "kernel/utils.h" -#include "kernel/sigtools.h" #include "kernel/ffinit.h" +#include "kernel/sigtools.h" +#include "kernel/utils.h" +#include "kernel/yosys.h" #include "libs/sha1/sha1.h" -#include #include +#include #include #include "simplemap.h" @@ -42,7 +42,7 @@ PRIVATE_NAMESPACE_BEGIN void apply_prefix(IdString prefix, IdString &id) { if (id[0] == '\\') - id = stringf("%s.%s", prefix.c_str(), id.c_str()+1); + id = stringf("%s.%s", prefix.c_str(), id.c_str() + 1); else id = stringf("$techmap%s.%s", prefix.c_str(), id.c_str()); } @@ -60,13 +60,12 @@ void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) sig = chunks; } -struct TechmapWorker -{ - dict simplemap_mappers; - dict>, RTLIL::Module*> techmap_cache; - dict techmap_do_cache; - pool module_queue; - dict sigmaps; +struct TechmapWorker { + dict simplemap_mappers; + dict>, RTLIL::Module *> techmap_cache; + dict techmap_do_cache; + pool module_queue; + dict sigmaps; pool log_msg_cache; @@ -98,9 +97,9 @@ struct TechmapWorker } else if (connbits_map.count(bit)) { if (verbose) log(" Bit %d of port %s and bit %d of port %s are connected.\n", i, log_id(conn.first), - connbits_map.at(bit).second, log_id(connbits_map.at(bit).first)); - constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i, - log_id(connbits_map.at(bit).first), connbits_map.at(bit).second); + connbits_map.at(bit).second, log_id(connbits_map.at(bit).first)); + constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i, log_id(connbits_map.at(bit).first), + connbits_map.at(bit).second); } else { connbits_map.emplace(bit, std::make_pair(conn.first, i)); constmap_info += stringf("|%s %d", log_id(conn.first), i); @@ -134,8 +133,8 @@ struct TechmapWorker if (!result.empty()) { SigMap sigmap(module); for (auto &it1 : result) - for (auto &it2 : it1.second) - sigmap.apply(it2.value); + for (auto &it2 : it1.second) + sigmap.apply(it2.value); } return result; @@ -146,7 +145,7 @@ struct TechmapWorker if (tpl->processes.size() != 0) { log("Technology map yielded processes:"); for (auto &it : tpl->processes) - log(" %s",log_id(it.first)); + log(" %s", log_id(it.first)); log("\n"); if (autoproc_mode) { Pass::call_on_module(tpl->design, tpl, "proc"); @@ -156,7 +155,6 @@ struct TechmapWorker } std::string orig_cell_name; - pool extra_src_attrs = cell->get_strpool_attribute(ID::src); orig_cell_name = cell->name.str(); for (auto tpl_cell : tpl->cells()) @@ -166,32 +164,28 @@ struct TechmapWorker } dict memory_renames; - for (auto &it : tpl->memories) { IdString m_name = it.first; apply_prefix(cell->name, m_name); RTLIL::Memory *m = module->addMemory(m_name, it.second); if (m->attributes.count(ID::src)) - m->add_strpool_attribute(ID::src, extra_src_attrs); + m->attributes[ID::src] = cell->attributes[ID::src]; memory_renames[it.first] = m->name; design->select(module, m); } dict positional_ports; - dict temp_renamed_wires; + dict temp_renamed_wires; pool autopurge_tpl_bits; - for (auto tpl_w : tpl->wires()) - { - if (tpl_w->port_id > 0) - { + for (auto tpl_w : tpl->wires()) { + if (tpl_w->port_id > 0) { IdString posportname = stringf("$%d", tpl_w->port_id); positional_ports.emplace(posportname, tpl_w->name); if (tpl_w->get_bool_attribute(ID::techmap_autopurge) && - (!cell->hasPort(tpl_w->name) || !GetSize(cell->getPort(tpl_w->name))) && - (!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname)))) - { + (!cell->hasPort(tpl_w->name) || !GetSize(cell->getPort(tpl_w->name))) && + (!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname)))) { if (sigmaps.count(tpl) == 0) sigmaps[tpl].set(tpl); @@ -217,7 +211,7 @@ struct TechmapWorker if (tpl_w->get_bool_attribute(ID::_techmap_special_)) w->attributes.clear(); if (w->attributes.count(ID::src)) - w->add_strpool_attribute(ID::src, extra_src_attrs); + w->attributes[ID::src] = cell->attributes[ID::src]; } design->select(module, w); @@ -230,24 +224,24 @@ struct TechmapWorker pool tpl_written_bits; for (auto tpl_cell : tpl->cells()) - for (auto &conn : tpl_cell->connections()) - if (tpl_cell->output(conn.first)) - for (auto bit : conn.second) - tpl_written_bits.insert(bit); + for (auto &conn : tpl_cell->connections()) + if (tpl_cell->output(conn.first)) + for (auto bit : conn.second) + tpl_written_bits.insert(bit); for (auto &conn : tpl->connections()) for (auto bit : conn.first) tpl_written_bits.insert(bit); SigMap port_signal_map; - for (auto &it : cell->connections()) - { + for (auto &it : cell->connections()) { IdString portname = it.first; if (positional_ports.count(portname) > 0) portname = positional_ports.at(portname); if (tpl->wire(portname) == nullptr || tpl->wire(portname)->port_id == 0) { if (portname.begins_with("$")) - log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str()); + log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), + tpl->name.c_str()); continue; } @@ -297,8 +291,7 @@ struct TechmapWorker if (w->port_output && !w->port_input) { port_signal_map.add(c.second, c.first); - } else - if (!w->port_output && w->port_input) { + } else if (!w->port_output && w->port_input) { port_signal_map.add(c.first, c.second); } else { module->connect(c); @@ -311,16 +304,15 @@ struct TechmapWorker auto lhs = GetSize(extra_connect.first); auto rhs = GetSize(extra_connect.second); if (lhs > rhs) - extra_connect.first.remove(rhs, lhs-rhs); + extra_connect.first.remove(rhs, lhs - rhs); else if (rhs > lhs) - extra_connect.second.remove(lhs, rhs-lhs); + extra_connect.second.remove(lhs, rhs - lhs); module->connect(extra_connect); break; } } - for (auto tpl_cell : tpl->cells()) - { + for (auto tpl_cell : tpl->cells()) { IdString c_name = tpl_cell->name; bool techmap_replace_cell = c_name.ends_with("_TECHMAP_REPLACE_"); @@ -339,8 +331,7 @@ struct TechmapWorker vector autopurge_ports; - for (auto &conn : c->connections()) - { + for (auto &conn : c->connections()) { bool autopurge = false; if (!autopurge_tpl_bits.empty()) { autopurge = GetSize(conn.second) != 0; @@ -375,7 +366,7 @@ struct TechmapWorker } if (c->attributes.count(ID::src)) - c->add_strpool_attribute(ID::src, extra_src_attrs); + c->attributes[ID::src] = cell->attributes[ID::src]; if (techmap_replace_cell) { for (auto attr : cell->attributes) @@ -396,8 +387,7 @@ struct TechmapWorker module->remove(cell); - for (auto &it : temp_renamed_wires) - { + for (auto &it : temp_renamed_wires) { Wire *w = it.first; IdString name = it.second; IdString altname = module->uniquify(name); @@ -407,8 +397,8 @@ struct TechmapWorker } } - bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, pool &handled_cells, - const dict> &celltypeMap, bool in_recursion) + bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, pool &handled_cells, + const dict> &celltypeMap, bool in_recursion) { std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping"; @@ -422,12 +412,11 @@ struct TechmapWorker SigMap sigmap(module); FfInitVals initvals(&sigmap, module); - TopoSort> cells; - dict> cell_to_inbit; - dict> outbit_to_cell; + TopoSort> cells; + dict> cell_to_inbit; + dict> outbit_to_cell; - for (auto cell : module->selected_cells()) - { + for (auto cell : module->selected_cells()) { if (handled_cells.count(cell) > 0) continue; @@ -441,8 +430,7 @@ struct TechmapWorker continue; } - for (auto &conn : cell->connections()) - { + for (auto &conn : cell->connections()) { RTLIL::SigSpec sig = sigmap(conn.second); sig.remove_const(); @@ -464,14 +452,13 @@ struct TechmapWorker } for (auto &it_right : cell_to_inbit) - for (auto &it_sigbit : it_right.second) - for (auto &it_left : outbit_to_cell[it_sigbit]) - cells.edge(it_left, it_right.first); + for (auto &it_sigbit : it_right.second) + for (auto &it_left : outbit_to_cell[it_sigbit]) + cells.edge(it_left, it_right.first); cells.sort(); - for (auto cell : cells.sorted) - { + for (auto cell : cells.sorted) { log_assert(handled_cells.count(cell) == 0); log_assert(cell == module->cell(cell->name)); bool mapped_cell = false; @@ -481,8 +468,7 @@ struct TechmapWorker if (in_recursion && cell->type.begins_with("\\$")) cell_type = cell_type.substr(1); - for (auto &tpl_name : celltypeMap.at(cell_type)) - { + for (auto &tpl_name : celltypeMap.at(cell_type)) { IdString derived_name = tpl_name; RTLIL::Module *tpl = map->module(tpl_name); dict parameters(cell->parameters); @@ -501,12 +487,10 @@ struct TechmapWorker if (tpl->attributes.count(ID::techmap_wrap)) extmapper_name = "wrap"; - if (!extmapper_name.empty()) - { + if (!extmapper_name.empty()) { cell->type = cell_type; - if ((extern_mode && !in_recursion) || extmapper_name == "wrap") - { + if ((extern_mode && !in_recursion) || extmapper_name == "wrap") { std::string m_name = stringf("$extern:%s:%s", extmapper_name.c_str(), log_id(cell->type)); for (auto &c : cell->parameters) @@ -518,8 +502,7 @@ struct TechmapWorker RTLIL::Design *extmapper_design = extern_mode && !in_recursion ? design : tpl->design; RTLIL::Module *extmapper_module = extmapper_design->module(m_name); - if (extmapper_module == nullptr) - { + if (extmapper_module == nullptr) { extmapper_module = extmapper_design->addModule(m_name); RTLIL::Cell *extmapper_cell = extmapper_module->addCell(cell->type, cell); @@ -542,7 +525,8 @@ struct TechmapWorker if (extmapper_name == "simplemap") { log("Creating %s with simplemap.\n", log_id(extmapper_module)); if (simplemap_mappers.count(extmapper_cell->type) == 0) - log_error("No simplemap mapper for cell type %s found!\n", log_id(extmapper_cell->type)); + log_error("No simplemap mapper for cell type %s found!\n", + log_id(extmapper_cell->type)); simplemap_mappers.at(extmapper_cell->type)(extmapper_module, extmapper_cell); extmapper_module->remove(extmapper_cell); } @@ -550,7 +534,8 @@ struct TechmapWorker if (extmapper_name == "maccmap") { log("Creating %s with maccmap.\n", log_id(extmapper_module)); if (extmapper_cell->type != ID($macc)) - log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(extmapper_cell->type)); + log_error("The maccmap mapper can only map $macc (not %s) cells!\n", + log_id(extmapper_cell->type)); maccmap(extmapper_module, extmapper_cell); extmapper_module->remove(extmapper_cell); } @@ -572,21 +557,23 @@ struct TechmapWorker goto use_wrapper_tpl; } - auto msg = stringf("Using extmapper %s for cells of type %s.", log_id(extmapper_module), log_id(cell->type)); + auto msg = + stringf("Using extmapper %s for cells of type %s.", log_id(extmapper_module), log_id(cell->type)); if (!log_msg_cache.count(msg)) { log_msg_cache.insert(msg); log("%s\n", msg.c_str()); } - log_debug("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module)); - } - else - { - auto msg = stringf("Using extmapper %s for cells of type %s.", extmapper_name.c_str(), log_id(cell->type)); + log_debug("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), + log_id(cell->type), log_id(extmapper_module)); + } else { + auto msg = + stringf("Using extmapper %s for cells of type %s.", extmapper_name.c_str(), log_id(cell->type)); if (!log_msg_cache.count(msg)) { log_msg_cache.insert(msg); log("%s\n", msg.c_str()); } - log_debug("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str()); + log_debug("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), + log_id(cell->type), extmapper_name.c_str()); if (extmapper_name == "simplemap") { if (simplemap_mappers.count(cell->type) == 0) @@ -596,7 +583,8 @@ struct TechmapWorker if (extmapper_name == "maccmap") { if (cell->type != ID($macc)) - log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(cell->type)); + log_error("The maccmap mapper can only map $macc (not %s) cells!\n", + log_id(cell->type)); maccmap(module, cell); } @@ -614,13 +602,14 @@ struct TechmapWorker continue; if (tpl->wire(conn.first) != nullptr && tpl->wire(conn.first)->port_id > 0) continue; - if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0) + if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || + tpl->avail_parameters.count(conn.first) == 0) goto next_tpl; parameters[conn.first] = conn.second.as_const(); } if (0) { - next_tpl: + next_tpl: continue; } @@ -634,14 +623,16 @@ struct TechmapWorker std::vector v = sigmap(conn.second).to_sigbit_vector(); for (auto &bit : v) bit = RTLIL::SigBit(bit.wire == nullptr ? RTLIL::State::S1 : RTLIL::State::S0); - parameters.emplace(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const()); + parameters.emplace(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first)), + RTLIL::SigSpec(v).as_const()); } if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first))) != 0) { std::vector v = sigmap(conn.second).to_sigbit_vector(); for (auto &bit : v) if (bit.wire != nullptr) bit = RTLIL::SigBit(RTLIL::State::Sx); - parameters.emplace(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const()); + parameters.emplace(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first)), + RTLIL::SigSpec(v).as_const()); } if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first))) != 0) { parameters.emplace(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first)), initvals(conn.second)); @@ -666,7 +657,7 @@ struct TechmapWorker // Find highest bit set int bits = 0; for (int i = 0; i < 32; i++) - if (((unique_bit_id_counter-1) & (1 << i)) != 0) + if (((unique_bit_id_counter - 1) & (1 << i)) != 0) bits = i; // Increment index by one to get number of bits bits++; @@ -688,7 +679,7 @@ struct TechmapWorker } if (0) { - use_wrapper_tpl:; + use_wrapper_tpl:; // do not register techmap_wrap modules with techmap_cache } else { std::pair> key(tpl_name, parameters); @@ -710,15 +701,13 @@ struct TechmapWorker if (constmapped_tpl != nullptr) tpl = constmapped_tpl; - if (techmap_do_cache.count(tpl) == 0) - { + if (techmap_do_cache.count(tpl) == 0) { bool keep_running = true; techmap_do_cache[tpl] = true; pool techmap_wire_names; - while (keep_running) - { + while (keep_running) { TechmapWires twd = techmap_find_special_wires(tpl); keep_running = false; @@ -731,8 +720,9 @@ struct TechmapWorker for (const TechmapWireData &elem : it.second) { RTLIL::SigSpec value = elem.value; if (value.is_fully_const() && value.as_bool()) { - log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n", - derived_name.c_str(), log_id(elem.wire->name), log_signal(value)); + log("Not using module `%s' from techmap as it contains a %s marker wire with " + "non-zero value %s.\n", + derived_name.c_str(), log_id(elem.wire->name), log_signal(value)); techmap_do_cache[tpl] = false; } } @@ -741,27 +731,26 @@ struct TechmapWorker if (!techmap_do_cache[tpl]) break; - for (auto &it : twd) - { + for (auto &it : twd) { if (!it.first.contains("_TECHMAP_DO_") || it.second.empty()) continue; auto &data = it.second.front(); if (!data.value.is_fully_const()) - log_error("Techmap yielded config wire %s with non-const value %s.\n", log_id(data.wire->name), log_signal(data.value)); + log_error("Techmap yielded config wire %s with non-const value %s.\n", + log_id(data.wire->name), log_signal(data.value)); techmap_wire_names.erase(it.first); const char *p = data.wire->name.c_str(); - const char *q = strrchr(p+1, '.'); - q = q ? q+1 : p+1; + const char *q = strrchr(p + 1, '.'); + q = q ? q + 1 : p + 1; std::string cmd_string = data.value.as_const().decode_string(); restart_eval_cmd_string: - if (cmd_string.rfind("CONSTMAP; ", 0) == 0) - { + if (cmd_string.rfind("CONSTMAP; ", 0) == 0) { cmd_string = cmd_string.substr(strlen("CONSTMAP; ")); log("Analyzing pattern of constant bits for this cell:\n"); @@ -780,8 +769,7 @@ struct TechmapWorker dict port_connmap; dict cellbits_to_tplbits; - for (auto wire : tpl->wires().to_vector()) - { + for (auto wire : tpl->wires().to_vector()) { if (!wire->port_input || wire->port_output) continue; @@ -793,14 +781,15 @@ struct TechmapWorker wire->port_id = 0; for (int i = 0; i < wire->width; i++) { - port_new2old_map.emplace(RTLIL::SigBit(new_wire, i), RTLIL::SigBit(wire, i)); - port_connmap.emplace(RTLIL::SigBit(wire, i), RTLIL::SigBit(new_wire, i)); + port_new2old_map.emplace(RTLIL::SigBit(new_wire, i), + RTLIL::SigBit(wire, i)); + port_connmap.emplace(RTLIL::SigBit(wire, i), + RTLIL::SigBit(new_wire, i)); } } // Handle outputs first, as these cannot be remapped. - for (auto &conn : cell->connections()) - { + for (auto &conn : cell->connections()) { Wire *twire = tpl->wire(conn.first); if (!twire->port_output) continue; @@ -813,28 +802,22 @@ struct TechmapWorker } // Now handle inputs, remapping as necessary. - for (auto &conn : cell->connections()) - { + for (auto &conn : cell->connections()) { Wire *twire = tpl->wire(conn.first); if (twire->port_output) continue; - for (int i = 0; i < GetSize(conn.second); i++) - { + for (int i = 0; i < GetSize(conn.second); i++) { RTLIL::SigBit bit = sigmap(conn.second[i]); RTLIL::SigBit tplbit(twire, i); - if (bit.wire == nullptr) - { + if (bit.wire == nullptr) { RTLIL::SigBit oldbit = port_new2old_map.at(tplbit); port_connmap.at(oldbit) = bit; - } - else if (cellbits_to_tplbits.count(bit)) - { + } else if (cellbits_to_tplbits.count(bit)) { RTLIL::SigBit oldbit = port_new2old_map.at(tplbit); port_connmap.at(oldbit) = cellbits_to_tplbits[bit]; - } - else + } else cellbits_to_tplbits[bit] = tplbit; } } @@ -850,17 +833,18 @@ struct TechmapWorker goto restart_eval_cmd_string; } - if (cmd_string.rfind("RECURSION; ", 0) == 0) - { + if (cmd_string.rfind("RECURSION; ", 0) == 0) { cmd_string = cmd_string.substr(strlen("RECURSION; ")); - while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } + while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { + } goto restart_eval_cmd_string; } Pass::call_on_module(map, tpl, cmd_string); log_assert(!strncmp(q, "_TECHMAP_DO_", 12)); - std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12); + std::string new_name = + data.wire->name.substr(0, q - p) + "_TECHMAP_DONE_" + data.wire->name.substr(q - p + 12); while (tpl->wire(new_name) != nullptr) new_name += "_"; tpl->rename(data.wire->name, new_name); @@ -872,12 +856,15 @@ struct TechmapWorker TechmapWires twd = techmap_find_special_wires(tpl); for (auto &it : twd) { - if (!it.first.ends_with("_TECHMAP_FAIL_") && (!it.first.begins_with("\\_TECHMAP_REMOVEINIT_") || !it.first.ends_with("_")) && !it.first.contains("_TECHMAP_DO_") && !it.first.contains("_TECHMAP_DONE_")) + if (!it.first.ends_with("_TECHMAP_FAIL_") && + (!it.first.begins_with("\\_TECHMAP_REMOVEINIT_") || !it.first.ends_with("_")) && + !it.first.contains("_TECHMAP_DO_") && !it.first.contains("_TECHMAP_DONE_")) log_error("Techmap yielded unknown config wire %s.\n", log_id(it.first)); if (techmap_do_cache[tpl]) for (auto &it2 : it.second) if (!it2.value.is_fully_const()) - log_error("Techmap yielded config wire %s with non-const value %s.\n", log_id(it2.wire->name), log_signal(it2.value)); + log_error("Techmap yielded config wire %s with non-const value %s.\n", + log_id(it2.wire->name), log_signal(it2.value)); techmap_wire_names.erase(it.first); } @@ -890,7 +877,8 @@ struct TechmapWorker log_continue = false; mkdebug.off(); } - while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } + while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { + } } } @@ -920,12 +908,10 @@ struct TechmapWorker } } - if (extern_mode && !in_recursion) - { + if (extern_mode && !in_recursion) { std::string m_name = stringf("$extern:%s", log_id(tpl)); - if (!design->module(m_name)) - { + if (!design->module(m_name)) { RTLIL::Module *m = design->addModule(m_name); tpl->cloneInto(m); @@ -940,15 +926,14 @@ struct TechmapWorker log_debug("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name)); cell->type = m_name; cell->parameters.clear(); - } - else - { + } else { auto msg = stringf("Using template %s for cells of type %s.", log_id(tpl), log_id(cell->type)); if (!log_msg_cache.count(msg)) { log_msg_cache.insert(msg); log("%s\n", msg.c_str()); } - log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(tpl)); + log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), + log_id(cell->type), log_id(tpl)); techmap_module_worker(design, module, cell, tpl); cell = nullptr; } @@ -974,7 +959,7 @@ struct TechmapWorker }; struct TechmapPass : public Pass { - TechmapPass() : Pass("techmap", "generic technology mapper") { } + TechmapPass() : Pass("techmap", "generic technology mapper") {} void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -1155,19 +1140,19 @@ struct TechmapPass : public Pass { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-map" && argidx+1 < args.size()) { + if (args[argidx] == "-map" && argidx + 1 < args.size()) { map_files.push_back(args[++argidx]); continue; } - if (args[argidx] == "-max_iter" && argidx+1 < args.size()) { + if (args[argidx] == "-max_iter" && argidx + 1 < args.size()) { max_iter = atoi(args[++argidx].c_str()); continue; } - if (args[argidx] == "-D" && argidx+1 < args.size()) { + if (args[argidx] == "-D" && argidx + 1 < args.size()) { verilog_frontend += " -D " + args[++argidx]; continue; } - if (args[argidx] == "-I" && argidx+1 < args.size()) { + if (args[argidx] == "-I" && argidx + 1 < args.size()) { verilog_frontend += " -I " + args[++argidx]; continue; } @@ -1203,13 +1188,15 @@ struct TechmapPass : public Pass { if (fn.compare(0, 1, "%") == 0) { if (!saved_designs.count(fn.substr(1))) { delete map; - log_cmd_error("Can't open saved design `%s'.\n", fn.c_str()+1); + log_cmd_error("Can't open saved design `%s'.\n", fn.c_str() + 1); } for (auto mod : saved_designs.at(fn.substr(1))->modules()) if (!map->module(mod->name)) map->add(mod->clone()); } else { - Frontend::frontend_call(map, nullptr, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "rtlil" : verilog_frontend)); + Frontend::frontend_call( + map, nullptr, fn, + (fn.size() > 3 && fn.compare(fn.size() - 3, std::string::npos, ".il") == 0 ? "rtlil" : verilog_frontend)); } } @@ -1235,15 +1222,15 @@ struct TechmapPass : public Pass { if (epos == std::string::npos) log_error("Malformed techmap_celltype pattern %s\n", q); for (size_t i = pos + 1; i < epos; i++) { - queue.push_back(name.substr(0, pos) + name[i] + name.substr(epos + 1, std::string::npos)); + queue.push_back(name.substr(0, pos) + name[i] + + name.substr(epos + 1, std::string::npos)); } } } } free(p); } else { - IdString module_name = module->name.begins_with("\\$") ? - module->name.substr(1) : module->name.str(); + IdString module_name = module->name.begins_with("\\$") ? module->name.substr(1) : module->name.str(); celltypeMap[module_name].insert(module->name); } } @@ -1260,14 +1247,13 @@ struct TechmapPass : public Pass { for (auto module : design->modules()) worker.module_queue.insert(module); - while (!worker.module_queue.empty()) - { + while (!worker.module_queue.empty()) { RTLIL::Module *module = *worker.module_queue.begin(); worker.module_queue.erase(module); int module_max_iter = max_iter; bool did_something = true; - pool handled_cells; + pool handled_cells; while (did_something) { did_something = false; if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false)) From 67f17004869c3aeea75c1e5620f73bfb1b34e7cd Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Fri, 29 Sep 2023 13:20:43 -0700 Subject: [PATCH 086/173] Revert formatting changes. --- passes/techmap/simplemap.cc | 200 ++++++++++++-------------- passes/techmap/techmap.cc | 274 +++++++++++++++++++----------------- 2 files changed, 235 insertions(+), 239 deletions(-) diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index 14c07922b14..7461460fed8 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -18,10 +18,10 @@ */ #include "simplemap.h" -#include "kernel/ff.h" #include "kernel/sigtools.h" -#include +#include "kernel/ff.h" #include +#include #include USING_YOSYS_NAMESPACE @@ -64,16 +64,11 @@ void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell) } IdString gate_type; - if (cell->type == ID($and)) - gate_type = ID($_AND_); - if (cell->type == ID($or)) - gate_type = ID($_OR_); - if (cell->type == ID($xor)) - gate_type = ID($_XOR_); - if (cell->type == ID($xnor)) - gate_type = ID($_XNOR_); - if (cell->type == ID($bweqx)) - gate_type = ID($_XNOR_); + if (cell->type == ID($and)) gate_type = ID($_AND_); + if (cell->type == ID($or)) gate_type = ID($_OR_); + if (cell->type == ID($xor)) gate_type = ID($_XOR_); + if (cell->type == ID($xnor)) gate_type = ID($_XNOR_); + if (cell->type == ID($bweqx)) gate_type = ID($_XNOR_); log_assert(!gate_type.empty()); for (int i = 0; i < GetSize(sig_y); i++) { @@ -94,44 +89,36 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) return; if (sig_a.size() == 0) { - if (cell->type == ID($reduce_and)) - module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); - if (cell->type == ID($reduce_or)) - module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); - if (cell->type == ID($reduce_xor)) - module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); - if (cell->type == ID($reduce_xnor)) - module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); - if (cell->type == ID($reduce_bool)) - module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == ID($reduce_and)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); + if (cell->type == ID($reduce_or)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == ID($reduce_xor)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == ID($reduce_xnor)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); + if (cell->type == ID($reduce_bool)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); return; } if (sig_y.size() > 1) { - module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size() - 1), RTLIL::SigSpec(0, sig_y.size() - 1))); + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); sig_y = sig_y.extract(0, 1); } IdString gate_type; - if (cell->type == ID($reduce_and)) - gate_type = ID($_AND_); - if (cell->type == ID($reduce_or)) - gate_type = ID($_OR_); - if (cell->type == ID($reduce_xor)) - gate_type = ID($_XOR_); - if (cell->type == ID($reduce_xnor)) - gate_type = ID($_XOR_); - if (cell->type == ID($reduce_bool)) - gate_type = ID($_OR_); + if (cell->type == ID($reduce_and)) gate_type = ID($_AND_); + if (cell->type == ID($reduce_or)) gate_type = ID($_OR_); + if (cell->type == ID($reduce_xor)) gate_type = ID($_XOR_); + if (cell->type == ID($reduce_xnor)) gate_type = ID($_XOR_); + if (cell->type == ID($reduce_bool)) gate_type = ID($_OR_); log_assert(!gate_type.empty()); RTLIL::Cell *last_output_cell = NULL; - while (sig_a.size() > 1) { + while (sig_a.size() > 1) + { RTLIL::SigSpec sig_t = module->addWire(NEW_ID, sig_a.size() / 2); - for (int i = 0; i < sig_a.size(); i += 2) { - if (i + 1 == sig_a.size()) { + for (int i = 0; i < sig_a.size(); i += 2) + { + if (i+1 == sig_a.size()) { sig_t.append(sig_a[i]); continue; } @@ -139,8 +126,8 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); - gate->setPort(ID::B, sig_a[i + 1]); - gate->setPort(ID::Y, sig_t[i / 2]); + gate->setPort(ID::B, sig_a[i+1]); + gate->setPort(ID::Y, sig_t[i/2]); last_output_cell = gate; } @@ -166,11 +153,13 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLIL::Cell *cell) { - while (sig.size() > 1) { + while (sig.size() > 1) + { RTLIL::SigSpec sig_t = module->addWire(NEW_ID, sig.size() / 2); - for (int i = 0; i < sig.size(); i += 2) { - if (i + 1 == sig.size()) { + for (int i = 0; i < sig.size(); i += 2) + { + if (i+1 == sig.size()) { sig_t.append(sig[i]); continue; } @@ -178,8 +167,8 @@ static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLIL::Cell RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_OR_)); gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig[i]); - gate->setPort(ID::B, sig[i + 1]); - gate->setPort(ID::Y, sig_t[i / 2]); + gate->setPort(ID::B, sig[i+1]); + gate->setPort(ID::Y, sig_t[i/2]); } sig = sig_t; @@ -200,7 +189,7 @@ void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell) return; if (sig_y.size() > 1) { - module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size() - 1), RTLIL::SigSpec(0, sig_y.size() - 1))); + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); sig_y = sig_y.extract(0, 1); } @@ -224,15 +213,13 @@ void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell) return; if (sig_y.size() > 1) { - module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size() - 1), RTLIL::SigSpec(0, sig_y.size() - 1))); + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); sig_y = sig_y.extract(0, 1); } IdString gate_type; - if (cell->type == ID($logic_and)) - gate_type = ID($_AND_); - if (cell->type == ID($logic_or)) - gate_type = ID($_OR_); + if (cell->type == ID($logic_and)) gate_type = ID($_AND_); + if (cell->type == ID($logic_or)) gate_type = ID($_OR_); log_assert(!gate_type.empty()); RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); @@ -253,22 +240,19 @@ void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell) RTLIL::SigSpec xor_out = module->addWire(NEW_ID, max(GetSize(sig_a), GetSize(sig_b))); RTLIL::Cell *xor_cell = module->addXor(NEW_ID, sig_a, sig_b, xor_out, is_signed); xor_cell->attributes[ID::src] = cell->attributes[ID::src]; - // xor_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); simplemap_bitop(module, xor_cell); module->remove(xor_cell); RTLIL::SigSpec reduce_out = is_ne ? sig_y : module->addWire(NEW_ID); RTLIL::Cell *reduce_cell = module->addReduceOr(NEW_ID, xor_out, reduce_out); reduce_cell->attributes[ID::src] = cell->attributes[ID::src]; - // reduce_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); simplemap_reduce(module, reduce_cell); module->remove(reduce_cell); if (!is_ne) { RTLIL::Cell *not_cell = module->addLogicNot(NEW_ID, reduce_out, sig_y); not_cell->attributes[ID::src] = cell->attributes[ID::src]; - // not_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - simplemap_lognot(module, not_cell); + simplemap_lognot(module, not_cell); module->remove(not_cell); } } @@ -328,15 +312,15 @@ void simplemap_bmux(RTLIL::Module *module, RTLIL::Cell *cell) int width = GetSize(cell->getPort(ID::Y)); for (int idx = 0; idx < GetSize(sel); idx++) { - SigSpec new_data = module->addWire(NEW_ID, GetSize(data) / 2); + SigSpec new_data = module->addWire(NEW_ID, GetSize(data)/2); for (int i = 0; i < GetSize(new_data); i += width) { for (int k = 0; k < width; k++) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); gate->attributes[ID::src] = cell->attributes[ID::src]; - gate->setPort(ID::A, data[i * 2 + k]); - gate->setPort(ID::B, data[i * 2 + width + k]); + gate->setPort(ID::A, data[i*2+k]); + gate->setPort(ID::B, data[i*2+width+k]); gate->setPort(ID::S, sel[idx]); - gate->setPort(ID::Y, new_data[i + k]); + gate->setPort(ID::Y, new_data[i+k]); } } data = new_data; @@ -352,14 +336,14 @@ void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell) lut_data.extend_u0(1 << cell->getParam(ID::WIDTH).as_int()); for (int idx = 0; GetSize(lut_data) > 1; idx++) { - SigSpec new_lut_data = module->addWire(NEW_ID, GetSize(lut_data) / 2); + SigSpec new_lut_data = module->addWire(NEW_ID, GetSize(lut_data)/2); for (int i = 0; i < GetSize(lut_data); i += 2) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, lut_data[i]); - gate->setPort(ID::B, lut_data[i + 1]); + gate->setPort(ID::B, lut_data[i+1]); gate->setPort(ID::S, lut_ctrl[idx]); - gate->setPort(ID::Y, new_lut_data[i / 2]); + gate->setPort(ID::Y, new_lut_data[i/2]); } lut_data = new_lut_data; } @@ -381,11 +365,11 @@ void simplemap_sop(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < depth; i++) { SigSpec in, pat; for (int j = 0; j < width; j++) { - if (table[2 * i * width + 2 * j + 0] == State::S1) { + if (table[2*i*width + 2*j + 0] == State::S1) { in.append(ctrl[j]); pat.append(State::S0); } - if (table[2 * i * width + 2 * j + 1] == State::S1) { + if (table[2*i*width + 2*j + 1] == State::S1) { in.append(ctrl[j]); pat.append(State::S1); } @@ -423,56 +407,56 @@ void simplemap_ff(RTLIL::Module *, RTLIL::Cell *cell) } } -void simplemap_get_mappers(dict &mappers) +void simplemap_get_mappers(dict &mappers) { - mappers[ID($not)] = simplemap_not; - mappers[ID($pos)] = simplemap_pos; - mappers[ID($and)] = simplemap_bitop; - mappers[ID($or)] = simplemap_bitop; - mappers[ID($xor)] = simplemap_bitop; - mappers[ID($xnor)] = simplemap_bitop; - mappers[ID($bweqx)] = simplemap_bitop; - mappers[ID($reduce_and)] = simplemap_reduce; - mappers[ID($reduce_or)] = simplemap_reduce; - mappers[ID($reduce_xor)] = simplemap_reduce; + mappers[ID($not)] = simplemap_not; + mappers[ID($pos)] = simplemap_pos; + mappers[ID($and)] = simplemap_bitop; + mappers[ID($or)] = simplemap_bitop; + mappers[ID($xor)] = simplemap_bitop; + mappers[ID($xnor)] = simplemap_bitop; + mappers[ID($bweqx)] = simplemap_bitop; + mappers[ID($reduce_and)] = simplemap_reduce; + mappers[ID($reduce_or)] = simplemap_reduce; + mappers[ID($reduce_xor)] = simplemap_reduce; mappers[ID($reduce_xnor)] = simplemap_reduce; mappers[ID($reduce_bool)] = simplemap_reduce; - mappers[ID($logic_not)] = simplemap_lognot; - mappers[ID($logic_and)] = simplemap_logbin; - mappers[ID($logic_or)] = simplemap_logbin; - mappers[ID($eq)] = simplemap_eqne; - mappers[ID($eqx)] = simplemap_eqne; - mappers[ID($ne)] = simplemap_eqne; - mappers[ID($nex)] = simplemap_eqne; - mappers[ID($mux)] = simplemap_mux; - mappers[ID($bwmux)] = simplemap_bwmux; - mappers[ID($tribuf)] = simplemap_tribuf; - mappers[ID($bmux)] = simplemap_bmux; - mappers[ID($lut)] = simplemap_lut; - mappers[ID($sop)] = simplemap_sop; - mappers[ID($slice)] = simplemap_slice; - mappers[ID($concat)] = simplemap_concat; - mappers[ID($sr)] = simplemap_ff; - mappers[ID($ff)] = simplemap_ff; - mappers[ID($dff)] = simplemap_ff; - mappers[ID($dffe)] = simplemap_ff; - mappers[ID($dffsr)] = simplemap_ff; - mappers[ID($dffsre)] = simplemap_ff; - mappers[ID($adff)] = simplemap_ff; - mappers[ID($sdff)] = simplemap_ff; - mappers[ID($adffe)] = simplemap_ff; - mappers[ID($sdffe)] = simplemap_ff; - mappers[ID($sdffce)] = simplemap_ff; - mappers[ID($aldff)] = simplemap_ff; - mappers[ID($aldffe)] = simplemap_ff; - mappers[ID($dlatch)] = simplemap_ff; - mappers[ID($adlatch)] = simplemap_ff; - mappers[ID($dlatchsr)] = simplemap_ff; + mappers[ID($logic_not)] = simplemap_lognot; + mappers[ID($logic_and)] = simplemap_logbin; + mappers[ID($logic_or)] = simplemap_logbin; + mappers[ID($eq)] = simplemap_eqne; + mappers[ID($eqx)] = simplemap_eqne; + mappers[ID($ne)] = simplemap_eqne; + mappers[ID($nex)] = simplemap_eqne; + mappers[ID($mux)] = simplemap_mux; + mappers[ID($bwmux)] = simplemap_bwmux; + mappers[ID($tribuf)] = simplemap_tribuf; + mappers[ID($bmux)] = simplemap_bmux; + mappers[ID($lut)] = simplemap_lut; + mappers[ID($sop)] = simplemap_sop; + mappers[ID($slice)] = simplemap_slice; + mappers[ID($concat)] = simplemap_concat; + mappers[ID($sr)] = simplemap_ff; + mappers[ID($ff)] = simplemap_ff; + mappers[ID($dff)] = simplemap_ff; + mappers[ID($dffe)] = simplemap_ff; + mappers[ID($dffsr)] = simplemap_ff; + mappers[ID($dffsre)] = simplemap_ff; + mappers[ID($adff)] = simplemap_ff; + mappers[ID($sdff)] = simplemap_ff; + mappers[ID($adffe)] = simplemap_ff; + mappers[ID($sdffe)] = simplemap_ff; + mappers[ID($sdffce)] = simplemap_ff; + mappers[ID($aldff)] = simplemap_ff; + mappers[ID($aldffe)] = simplemap_ff; + mappers[ID($dlatch)] = simplemap_ff; + mappers[ID($adlatch)] = simplemap_ff; + mappers[ID($dlatchsr)] = simplemap_ff; } void simplemap(RTLIL::Module *module, RTLIL::Cell *cell) { - static dict mappers; + static dict mappers; static bool initialized_mappers = false; if (!initialized_mappers) { @@ -487,7 +471,7 @@ YOSYS_NAMESPACE_END PRIVATE_NAMESPACE_BEGIN struct SimplemapPass : public Pass { - SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") {} + SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") { } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -509,13 +493,13 @@ struct SimplemapPass : public Pass { log_header(design, "Executing SIMPLEMAP pass (map simple cells to gate primitives).\n"); extra_args(args, 1, design); - dict mappers; + dict mappers; simplemap_get_mappers(mappers); for (auto mod : design->modules()) { if (!design->selected(mod) || mod->get_blackbox_attribute()) continue; - std::vector cells = mod->cells(); + std::vector cells = mod->cells(); for (auto cell : cells) { if (mappers.count(cell->type) == 0) continue; diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 52a24dcf3ba..23d0d93fc57 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -17,14 +17,14 @@ * */ -#include "kernel/ffinit.h" -#include "kernel/sigtools.h" -#include "kernel/utils.h" #include "kernel/yosys.h" +#include "kernel/utils.h" +#include "kernel/sigtools.h" +#include "kernel/ffinit.h" #include "libs/sha1/sha1.h" -#include #include +#include #include #include "simplemap.h" @@ -42,7 +42,7 @@ PRIVATE_NAMESPACE_BEGIN void apply_prefix(IdString prefix, IdString &id) { if (id[0] == '\\') - id = stringf("%s.%s", prefix.c_str(), id.c_str() + 1); + id = stringf("%s.%s", prefix.c_str(), id.c_str()+1); else id = stringf("$techmap%s.%s", prefix.c_str(), id.c_str()); } @@ -60,12 +60,13 @@ void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) sig = chunks; } -struct TechmapWorker { - dict simplemap_mappers; - dict>, RTLIL::Module *> techmap_cache; - dict techmap_do_cache; - pool module_queue; - dict sigmaps; +struct TechmapWorker +{ + dict simplemap_mappers; + dict>, RTLIL::Module*> techmap_cache; + dict techmap_do_cache; + pool module_queue; + dict sigmaps; pool log_msg_cache; @@ -97,9 +98,9 @@ struct TechmapWorker { } else if (connbits_map.count(bit)) { if (verbose) log(" Bit %d of port %s and bit %d of port %s are connected.\n", i, log_id(conn.first), - connbits_map.at(bit).second, log_id(connbits_map.at(bit).first)); - constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i, log_id(connbits_map.at(bit).first), - connbits_map.at(bit).second); + connbits_map.at(bit).second, log_id(connbits_map.at(bit).first)); + constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i, + log_id(connbits_map.at(bit).first), connbits_map.at(bit).second); } else { connbits_map.emplace(bit, std::make_pair(conn.first, i)); constmap_info += stringf("|%s %d", log_id(conn.first), i); @@ -133,8 +134,8 @@ struct TechmapWorker { if (!result.empty()) { SigMap sigmap(module); for (auto &it1 : result) - for (auto &it2 : it1.second) - sigmap.apply(it2.value); + for (auto &it2 : it1.second) + sigmap.apply(it2.value); } return result; @@ -145,7 +146,7 @@ struct TechmapWorker { if (tpl->processes.size() != 0) { log("Technology map yielded processes:"); for (auto &it : tpl->processes) - log(" %s", log_id(it.first)); + log(" %s",log_id(it.first)); log("\n"); if (autoproc_mode) { Pass::call_on_module(tpl->design, tpl, "proc"); @@ -155,7 +156,6 @@ struct TechmapWorker { } std::string orig_cell_name; - orig_cell_name = cell->name.str(); for (auto tpl_cell : tpl->cells()) if (tpl_cell->name.ends_with("_TECHMAP_REPLACE_")) { @@ -164,28 +164,32 @@ struct TechmapWorker { } dict memory_renames; + for (auto &it : tpl->memories) { IdString m_name = it.first; apply_prefix(cell->name, m_name); RTLIL::Memory *m = module->addMemory(m_name, it.second); if (m->attributes.count(ID::src)) - m->attributes[ID::src] = cell->attributes[ID::src]; + m->attributes[ID::src] = cell->attributes[ID::src]; memory_renames[it.first] = m->name; design->select(module, m); } dict positional_ports; - dict temp_renamed_wires; + dict temp_renamed_wires; pool autopurge_tpl_bits; - for (auto tpl_w : tpl->wires()) { - if (tpl_w->port_id > 0) { + for (auto tpl_w : tpl->wires()) + { + if (tpl_w->port_id > 0) + { IdString posportname = stringf("$%d", tpl_w->port_id); positional_ports.emplace(posportname, tpl_w->name); if (tpl_w->get_bool_attribute(ID::techmap_autopurge) && - (!cell->hasPort(tpl_w->name) || !GetSize(cell->getPort(tpl_w->name))) && - (!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname)))) { + (!cell->hasPort(tpl_w->name) || !GetSize(cell->getPort(tpl_w->name))) && + (!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname)))) + { if (sigmaps.count(tpl) == 0) sigmaps[tpl].set(tpl); @@ -211,7 +215,7 @@ struct TechmapWorker { if (tpl_w->get_bool_attribute(ID::_techmap_special_)) w->attributes.clear(); if (w->attributes.count(ID::src)) - w->attributes[ID::src] = cell->attributes[ID::src]; + w->attributes[ID::src] = cell->attributes[ID::src]; } design->select(module, w); @@ -224,24 +228,24 @@ struct TechmapWorker { pool tpl_written_bits; for (auto tpl_cell : tpl->cells()) - for (auto &conn : tpl_cell->connections()) - if (tpl_cell->output(conn.first)) - for (auto bit : conn.second) - tpl_written_bits.insert(bit); + for (auto &conn : tpl_cell->connections()) + if (tpl_cell->output(conn.first)) + for (auto bit : conn.second) + tpl_written_bits.insert(bit); for (auto &conn : tpl->connections()) for (auto bit : conn.first) tpl_written_bits.insert(bit); SigMap port_signal_map; - for (auto &it : cell->connections()) { + for (auto &it : cell->connections()) + { IdString portname = it.first; if (positional_ports.count(portname) > 0) portname = positional_ports.at(portname); if (tpl->wire(portname) == nullptr || tpl->wire(portname)->port_id == 0) { if (portname.begins_with("$")) - log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), - tpl->name.c_str()); + log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str()); continue; } @@ -291,7 +295,8 @@ struct TechmapWorker { if (w->port_output && !w->port_input) { port_signal_map.add(c.second, c.first); - } else if (!w->port_output && w->port_input) { + } else + if (!w->port_output && w->port_input) { port_signal_map.add(c.first, c.second); } else { module->connect(c); @@ -304,15 +309,16 @@ struct TechmapWorker { auto lhs = GetSize(extra_connect.first); auto rhs = GetSize(extra_connect.second); if (lhs > rhs) - extra_connect.first.remove(rhs, lhs - rhs); + extra_connect.first.remove(rhs, lhs-rhs); else if (rhs > lhs) - extra_connect.second.remove(lhs, rhs - lhs); + extra_connect.second.remove(lhs, rhs-lhs); module->connect(extra_connect); break; } } - for (auto tpl_cell : tpl->cells()) { + for (auto tpl_cell : tpl->cells()) + { IdString c_name = tpl_cell->name; bool techmap_replace_cell = c_name.ends_with("_TECHMAP_REPLACE_"); @@ -331,7 +337,8 @@ struct TechmapWorker { vector autopurge_ports; - for (auto &conn : c->connections()) { + for (auto &conn : c->connections()) + { bool autopurge = false; if (!autopurge_tpl_bits.empty()) { autopurge = GetSize(conn.second) != 0; @@ -366,7 +373,7 @@ struct TechmapWorker { } if (c->attributes.count(ID::src)) - c->attributes[ID::src] = cell->attributes[ID::src]; + c->attributes[ID::src] = cell->attributes[ID::src]; if (techmap_replace_cell) { for (auto attr : cell->attributes) @@ -387,7 +394,8 @@ struct TechmapWorker { module->remove(cell); - for (auto &it : temp_renamed_wires) { + for (auto &it : temp_renamed_wires) + { Wire *w = it.first; IdString name = it.second; IdString altname = module->uniquify(name); @@ -397,8 +405,8 @@ struct TechmapWorker { } } - bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, pool &handled_cells, - const dict> &celltypeMap, bool in_recursion) + bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, pool &handled_cells, + const dict> &celltypeMap, bool in_recursion) { std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping"; @@ -412,11 +420,12 @@ struct TechmapWorker { SigMap sigmap(module); FfInitVals initvals(&sigmap, module); - TopoSort> cells; - dict> cell_to_inbit; - dict> outbit_to_cell; + TopoSort> cells; + dict> cell_to_inbit; + dict> outbit_to_cell; - for (auto cell : module->selected_cells()) { + for (auto cell : module->selected_cells()) + { if (handled_cells.count(cell) > 0) continue; @@ -430,7 +439,8 @@ struct TechmapWorker { continue; } - for (auto &conn : cell->connections()) { + for (auto &conn : cell->connections()) + { RTLIL::SigSpec sig = sigmap(conn.second); sig.remove_const(); @@ -452,13 +462,14 @@ struct TechmapWorker { } for (auto &it_right : cell_to_inbit) - for (auto &it_sigbit : it_right.second) - for (auto &it_left : outbit_to_cell[it_sigbit]) - cells.edge(it_left, it_right.first); + for (auto &it_sigbit : it_right.second) + for (auto &it_left : outbit_to_cell[it_sigbit]) + cells.edge(it_left, it_right.first); cells.sort(); - for (auto cell : cells.sorted) { + for (auto cell : cells.sorted) + { log_assert(handled_cells.count(cell) == 0); log_assert(cell == module->cell(cell->name)); bool mapped_cell = false; @@ -468,7 +479,8 @@ struct TechmapWorker { if (in_recursion && cell->type.begins_with("\\$")) cell_type = cell_type.substr(1); - for (auto &tpl_name : celltypeMap.at(cell_type)) { + for (auto &tpl_name : celltypeMap.at(cell_type)) + { IdString derived_name = tpl_name; RTLIL::Module *tpl = map->module(tpl_name); dict parameters(cell->parameters); @@ -487,10 +499,12 @@ struct TechmapWorker { if (tpl->attributes.count(ID::techmap_wrap)) extmapper_name = "wrap"; - if (!extmapper_name.empty()) { + if (!extmapper_name.empty()) + { cell->type = cell_type; - if ((extern_mode && !in_recursion) || extmapper_name == "wrap") { + if ((extern_mode && !in_recursion) || extmapper_name == "wrap") + { std::string m_name = stringf("$extern:%s:%s", extmapper_name.c_str(), log_id(cell->type)); for (auto &c : cell->parameters) @@ -502,7 +516,8 @@ struct TechmapWorker { RTLIL::Design *extmapper_design = extern_mode && !in_recursion ? design : tpl->design; RTLIL::Module *extmapper_module = extmapper_design->module(m_name); - if (extmapper_module == nullptr) { + if (extmapper_module == nullptr) + { extmapper_module = extmapper_design->addModule(m_name); RTLIL::Cell *extmapper_cell = extmapper_module->addCell(cell->type, cell); @@ -525,8 +540,7 @@ struct TechmapWorker { if (extmapper_name == "simplemap") { log("Creating %s with simplemap.\n", log_id(extmapper_module)); if (simplemap_mappers.count(extmapper_cell->type) == 0) - log_error("No simplemap mapper for cell type %s found!\n", - log_id(extmapper_cell->type)); + log_error("No simplemap mapper for cell type %s found!\n", log_id(extmapper_cell->type)); simplemap_mappers.at(extmapper_cell->type)(extmapper_module, extmapper_cell); extmapper_module->remove(extmapper_cell); } @@ -534,8 +548,7 @@ struct TechmapWorker { if (extmapper_name == "maccmap") { log("Creating %s with maccmap.\n", log_id(extmapper_module)); if (extmapper_cell->type != ID($macc)) - log_error("The maccmap mapper can only map $macc (not %s) cells!\n", - log_id(extmapper_cell->type)); + log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(extmapper_cell->type)); maccmap(extmapper_module, extmapper_cell); extmapper_module->remove(extmapper_cell); } @@ -557,23 +570,21 @@ struct TechmapWorker { goto use_wrapper_tpl; } - auto msg = - stringf("Using extmapper %s for cells of type %s.", log_id(extmapper_module), log_id(cell->type)); + auto msg = stringf("Using extmapper %s for cells of type %s.", log_id(extmapper_module), log_id(cell->type)); if (!log_msg_cache.count(msg)) { log_msg_cache.insert(msg); log("%s\n", msg.c_str()); } - log_debug("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), - log_id(cell->type), log_id(extmapper_module)); - } else { - auto msg = - stringf("Using extmapper %s for cells of type %s.", extmapper_name.c_str(), log_id(cell->type)); + log_debug("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module)); + } + else + { + auto msg = stringf("Using extmapper %s for cells of type %s.", extmapper_name.c_str(), log_id(cell->type)); if (!log_msg_cache.count(msg)) { log_msg_cache.insert(msg); log("%s\n", msg.c_str()); } - log_debug("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), - log_id(cell->type), extmapper_name.c_str()); + log_debug("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str()); if (extmapper_name == "simplemap") { if (simplemap_mappers.count(cell->type) == 0) @@ -583,8 +594,7 @@ struct TechmapWorker { if (extmapper_name == "maccmap") { if (cell->type != ID($macc)) - log_error("The maccmap mapper can only map $macc (not %s) cells!\n", - log_id(cell->type)); + log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(cell->type)); maccmap(module, cell); } @@ -602,14 +612,13 @@ struct TechmapWorker { continue; if (tpl->wire(conn.first) != nullptr && tpl->wire(conn.first)->port_id > 0) continue; - if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || - tpl->avail_parameters.count(conn.first) == 0) + if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0) goto next_tpl; parameters[conn.first] = conn.second.as_const(); } if (0) { - next_tpl: + next_tpl: continue; } @@ -623,16 +632,14 @@ struct TechmapWorker { std::vector v = sigmap(conn.second).to_sigbit_vector(); for (auto &bit : v) bit = RTLIL::SigBit(bit.wire == nullptr ? RTLIL::State::S1 : RTLIL::State::S0); - parameters.emplace(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first)), - RTLIL::SigSpec(v).as_const()); + parameters.emplace(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const()); } if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first))) != 0) { std::vector v = sigmap(conn.second).to_sigbit_vector(); for (auto &bit : v) if (bit.wire != nullptr) bit = RTLIL::SigBit(RTLIL::State::Sx); - parameters.emplace(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first)), - RTLIL::SigSpec(v).as_const()); + parameters.emplace(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const()); } if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first))) != 0) { parameters.emplace(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first)), initvals(conn.second)); @@ -657,7 +664,7 @@ struct TechmapWorker { // Find highest bit set int bits = 0; for (int i = 0; i < 32; i++) - if (((unique_bit_id_counter - 1) & (1 << i)) != 0) + if (((unique_bit_id_counter-1) & (1 << i)) != 0) bits = i; // Increment index by one to get number of bits bits++; @@ -679,7 +686,7 @@ struct TechmapWorker { } if (0) { - use_wrapper_tpl:; + use_wrapper_tpl:; // do not register techmap_wrap modules with techmap_cache } else { std::pair> key(tpl_name, parameters); @@ -701,13 +708,15 @@ struct TechmapWorker { if (constmapped_tpl != nullptr) tpl = constmapped_tpl; - if (techmap_do_cache.count(tpl) == 0) { + if (techmap_do_cache.count(tpl) == 0) + { bool keep_running = true; techmap_do_cache[tpl] = true; pool techmap_wire_names; - while (keep_running) { + while (keep_running) + { TechmapWires twd = techmap_find_special_wires(tpl); keep_running = false; @@ -720,9 +729,8 @@ struct TechmapWorker { for (const TechmapWireData &elem : it.second) { RTLIL::SigSpec value = elem.value; if (value.is_fully_const() && value.as_bool()) { - log("Not using module `%s' from techmap as it contains a %s marker wire with " - "non-zero value %s.\n", - derived_name.c_str(), log_id(elem.wire->name), log_signal(value)); + log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n", + derived_name.c_str(), log_id(elem.wire->name), log_signal(value)); techmap_do_cache[tpl] = false; } } @@ -731,26 +739,27 @@ struct TechmapWorker { if (!techmap_do_cache[tpl]) break; - for (auto &it : twd) { + for (auto &it : twd) + { if (!it.first.contains("_TECHMAP_DO_") || it.second.empty()) continue; auto &data = it.second.front(); if (!data.value.is_fully_const()) - log_error("Techmap yielded config wire %s with non-const value %s.\n", - log_id(data.wire->name), log_signal(data.value)); + log_error("Techmap yielded config wire %s with non-const value %s.\n", log_id(data.wire->name), log_signal(data.value)); techmap_wire_names.erase(it.first); const char *p = data.wire->name.c_str(); - const char *q = strrchr(p + 1, '.'); - q = q ? q + 1 : p + 1; + const char *q = strrchr(p+1, '.'); + q = q ? q+1 : p+1; std::string cmd_string = data.value.as_const().decode_string(); restart_eval_cmd_string: - if (cmd_string.rfind("CONSTMAP; ", 0) == 0) { + if (cmd_string.rfind("CONSTMAP; ", 0) == 0) + { cmd_string = cmd_string.substr(strlen("CONSTMAP; ")); log("Analyzing pattern of constant bits for this cell:\n"); @@ -769,7 +778,8 @@ struct TechmapWorker { dict port_connmap; dict cellbits_to_tplbits; - for (auto wire : tpl->wires().to_vector()) { + for (auto wire : tpl->wires().to_vector()) + { if (!wire->port_input || wire->port_output) continue; @@ -781,15 +791,14 @@ struct TechmapWorker { wire->port_id = 0; for (int i = 0; i < wire->width; i++) { - port_new2old_map.emplace(RTLIL::SigBit(new_wire, i), - RTLIL::SigBit(wire, i)); - port_connmap.emplace(RTLIL::SigBit(wire, i), - RTLIL::SigBit(new_wire, i)); + port_new2old_map.emplace(RTLIL::SigBit(new_wire, i), RTLIL::SigBit(wire, i)); + port_connmap.emplace(RTLIL::SigBit(wire, i), RTLIL::SigBit(new_wire, i)); } } // Handle outputs first, as these cannot be remapped. - for (auto &conn : cell->connections()) { + for (auto &conn : cell->connections()) + { Wire *twire = tpl->wire(conn.first); if (!twire->port_output) continue; @@ -802,22 +811,28 @@ struct TechmapWorker { } // Now handle inputs, remapping as necessary. - for (auto &conn : cell->connections()) { + for (auto &conn : cell->connections()) + { Wire *twire = tpl->wire(conn.first); if (twire->port_output) continue; - for (int i = 0; i < GetSize(conn.second); i++) { + for (int i = 0; i < GetSize(conn.second); i++) + { RTLIL::SigBit bit = sigmap(conn.second[i]); RTLIL::SigBit tplbit(twire, i); - if (bit.wire == nullptr) { + if (bit.wire == nullptr) + { RTLIL::SigBit oldbit = port_new2old_map.at(tplbit); port_connmap.at(oldbit) = bit; - } else if (cellbits_to_tplbits.count(bit)) { + } + else if (cellbits_to_tplbits.count(bit)) + { RTLIL::SigBit oldbit = port_new2old_map.at(tplbit); port_connmap.at(oldbit) = cellbits_to_tplbits[bit]; - } else + } + else cellbits_to_tplbits[bit] = tplbit; } } @@ -833,18 +848,17 @@ struct TechmapWorker { goto restart_eval_cmd_string; } - if (cmd_string.rfind("RECURSION; ", 0) == 0) { + if (cmd_string.rfind("RECURSION; ", 0) == 0) + { cmd_string = cmd_string.substr(strlen("RECURSION; ")); - while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { - } + while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } goto restart_eval_cmd_string; } Pass::call_on_module(map, tpl, cmd_string); log_assert(!strncmp(q, "_TECHMAP_DO_", 12)); - std::string new_name = - data.wire->name.substr(0, q - p) + "_TECHMAP_DONE_" + data.wire->name.substr(q - p + 12); + std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12); while (tpl->wire(new_name) != nullptr) new_name += "_"; tpl->rename(data.wire->name, new_name); @@ -856,15 +870,12 @@ struct TechmapWorker { TechmapWires twd = techmap_find_special_wires(tpl); for (auto &it : twd) { - if (!it.first.ends_with("_TECHMAP_FAIL_") && - (!it.first.begins_with("\\_TECHMAP_REMOVEINIT_") || !it.first.ends_with("_")) && - !it.first.contains("_TECHMAP_DO_") && !it.first.contains("_TECHMAP_DONE_")) + if (!it.first.ends_with("_TECHMAP_FAIL_") && (!it.first.begins_with("\\_TECHMAP_REMOVEINIT_") || !it.first.ends_with("_")) && !it.first.contains("_TECHMAP_DO_") && !it.first.contains("_TECHMAP_DONE_")) log_error("Techmap yielded unknown config wire %s.\n", log_id(it.first)); if (techmap_do_cache[tpl]) for (auto &it2 : it.second) if (!it2.value.is_fully_const()) - log_error("Techmap yielded config wire %s with non-const value %s.\n", - log_id(it2.wire->name), log_signal(it2.value)); + log_error("Techmap yielded config wire %s with non-const value %s.\n", log_id(it2.wire->name), log_signal(it2.value)); techmap_wire_names.erase(it.first); } @@ -877,8 +888,7 @@ struct TechmapWorker { log_continue = false; mkdebug.off(); } - while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { - } + while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } } } @@ -908,10 +918,12 @@ struct TechmapWorker { } } - if (extern_mode && !in_recursion) { + if (extern_mode && !in_recursion) + { std::string m_name = stringf("$extern:%s", log_id(tpl)); - if (!design->module(m_name)) { + if (!design->module(m_name)) + { RTLIL::Module *m = design->addModule(m_name); tpl->cloneInto(m); @@ -926,14 +938,15 @@ struct TechmapWorker { log_debug("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name)); cell->type = m_name; cell->parameters.clear(); - } else { + } + else + { auto msg = stringf("Using template %s for cells of type %s.", log_id(tpl), log_id(cell->type)); if (!log_msg_cache.count(msg)) { log_msg_cache.insert(msg); log("%s\n", msg.c_str()); } - log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), - log_id(cell->type), log_id(tpl)); + log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(tpl)); techmap_module_worker(design, module, cell, tpl); cell = nullptr; } @@ -959,7 +972,7 @@ struct TechmapWorker { }; struct TechmapPass : public Pass { - TechmapPass() : Pass("techmap", "generic technology mapper") {} + TechmapPass() : Pass("techmap", "generic technology mapper") { } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -1140,19 +1153,19 @@ struct TechmapPass : public Pass { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-map" && argidx + 1 < args.size()) { + if (args[argidx] == "-map" && argidx+1 < args.size()) { map_files.push_back(args[++argidx]); continue; } - if (args[argidx] == "-max_iter" && argidx + 1 < args.size()) { + if (args[argidx] == "-max_iter" && argidx+1 < args.size()) { max_iter = atoi(args[++argidx].c_str()); continue; } - if (args[argidx] == "-D" && argidx + 1 < args.size()) { + if (args[argidx] == "-D" && argidx+1 < args.size()) { verilog_frontend += " -D " + args[++argidx]; continue; } - if (args[argidx] == "-I" && argidx + 1 < args.size()) { + if (args[argidx] == "-I" && argidx+1 < args.size()) { verilog_frontend += " -I " + args[++argidx]; continue; } @@ -1188,15 +1201,13 @@ struct TechmapPass : public Pass { if (fn.compare(0, 1, "%") == 0) { if (!saved_designs.count(fn.substr(1))) { delete map; - log_cmd_error("Can't open saved design `%s'.\n", fn.c_str() + 1); + log_cmd_error("Can't open saved design `%s'.\n", fn.c_str()+1); } for (auto mod : saved_designs.at(fn.substr(1))->modules()) if (!map->module(mod->name)) map->add(mod->clone()); } else { - Frontend::frontend_call( - map, nullptr, fn, - (fn.size() > 3 && fn.compare(fn.size() - 3, std::string::npos, ".il") == 0 ? "rtlil" : verilog_frontend)); + Frontend::frontend_call(map, nullptr, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "rtlil" : verilog_frontend)); } } @@ -1222,15 +1233,15 @@ struct TechmapPass : public Pass { if (epos == std::string::npos) log_error("Malformed techmap_celltype pattern %s\n", q); for (size_t i = pos + 1; i < epos; i++) { - queue.push_back(name.substr(0, pos) + name[i] + - name.substr(epos + 1, std::string::npos)); + queue.push_back(name.substr(0, pos) + name[i] + name.substr(epos + 1, std::string::npos)); } } } } free(p); } else { - IdString module_name = module->name.begins_with("\\$") ? module->name.substr(1) : module->name.str(); + IdString module_name = module->name.begins_with("\\$") ? + module->name.substr(1) : module->name.str(); celltypeMap[module_name].insert(module->name); } } @@ -1247,13 +1258,14 @@ struct TechmapPass : public Pass { for (auto module : design->modules()) worker.module_queue.insert(module); - while (!worker.module_queue.empty()) { + while (!worker.module_queue.empty()) + { RTLIL::Module *module = *worker.module_queue.begin(); worker.module_queue.erase(module); int module_max_iter = max_iter; bool did_something = true; - pool handled_cells; + pool handled_cells; while (did_something) { did_something = false; if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false)) From 1bbc12f389a131e8af65dece57ba25d8c96b77d0 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Fri, 29 Sep 2023 15:17:42 -0700 Subject: [PATCH 087/173] Revert changes to techmap.cc. --- passes/techmap/techmap.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 23d0d93fc57..144f596c88c 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -156,6 +156,8 @@ struct TechmapWorker } std::string orig_cell_name; + pool extra_src_attrs = cell->get_strpool_attribute(ID::src); + orig_cell_name = cell->name.str(); for (auto tpl_cell : tpl->cells()) if (tpl_cell->name.ends_with("_TECHMAP_REPLACE_")) { @@ -170,7 +172,7 @@ struct TechmapWorker apply_prefix(cell->name, m_name); RTLIL::Memory *m = module->addMemory(m_name, it.second); if (m->attributes.count(ID::src)) - m->attributes[ID::src] = cell->attributes[ID::src]; + m->add_strpool_attribute(ID::src, extra_src_attrs); memory_renames[it.first] = m->name; design->select(module, m); } @@ -215,7 +217,7 @@ struct TechmapWorker if (tpl_w->get_bool_attribute(ID::_techmap_special_)) w->attributes.clear(); if (w->attributes.count(ID::src)) - w->attributes[ID::src] = cell->attributes[ID::src]; + w->add_strpool_attribute(ID::src, extra_src_attrs); } design->select(module, w); @@ -373,7 +375,7 @@ struct TechmapWorker } if (c->attributes.count(ID::src)) - c->attributes[ID::src] = cell->attributes[ID::src]; + c->add_strpool_attribute(ID::src, extra_src_attrs); if (techmap_replace_cell) { for (auto attr : cell->attributes) From bce984fa60fed1b46a95383d0737eb620fb0c340 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 2 Oct 2023 15:57:18 -0700 Subject: [PATCH 088/173] Speed up OptMergePass by 1.7x. The main speedup comes from swithing from using a SHA1 hash to std::hash. There is no need to use an expensive cryptographic hash for fingerprinting in this context. --- kernel/celltypes.h | 10 +++++----- kernel/rtlil.h | 6 +++++- passes/opt/opt_merge.cc | 11 +++++------ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/kernel/celltypes.h b/kernel/celltypes.h index cad505d9afd..58c6907dc63 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -56,7 +56,7 @@ struct CellTypes setup_stdcells_mem(); } - void setup_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, bool is_evaluable = false) + void setup_type(const RTLIL::IdString& type, const pool &inputs, const pool &outputs, bool is_evaluable = false) { CellType ct = {type, inputs, outputs, is_evaluable}; cell_types[ct.type] = ct; @@ -298,24 +298,24 @@ struct CellTypes cell_types.clear(); } - bool cell_known(RTLIL::IdString type) const + bool cell_known(const RTLIL::IdString& type) const { return cell_types.count(type) != 0; } - bool cell_output(RTLIL::IdString type, RTLIL::IdString port) const + bool cell_output(const RTLIL::IdString& type, const RTLIL::IdString& port) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.outputs.count(port) != 0; } - bool cell_input(RTLIL::IdString type, RTLIL::IdString port) const + bool cell_input(const RTLIL::IdString& type, const RTLIL::IdString& port) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.inputs.count(port) != 0; } - bool cell_evaluable(RTLIL::IdString type) const + bool cell_evaluable(const RTLIL::IdString& type) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.is_evaluable; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index c50d75e9087..f53d9df8c84 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -308,10 +308,14 @@ namespace RTLIL bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; } char operator[](size_t i) const { - const char *p = c_str(); + const char *p = c_str(); +#ifndef NDEBUG for (; i != 0; i--, p++) log_assert(*p != 0); return *p; +#else + return *(p + i); +#endif } std::string substr(size_t pos = 0, size_t len = std::string::npos) const { diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index e9d98cd4304..4bcd5a18947 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -41,7 +41,7 @@ struct OptMergeWorker CellTypes ct; int total_count; - SHA1 checksum; + using FingerPrint = std::hash::result_type; static void sort_pmux_conn(dict &conn) { @@ -78,7 +78,7 @@ struct OptMergeWorker return str; } - std::string hash_cell_parameters_and_connections(const RTLIL::Cell *cell) + FingerPrint hash_cell_parameters_and_connections(const RTLIL::Cell *cell) { vector hash_conn_strings; std::string hash_string = cell->type.str() + "\n"; @@ -149,8 +149,7 @@ struct OptMergeWorker for (auto it : hash_conn_strings) hash_string += it; - checksum.update(hash_string); - return checksum.final(); + return std::hash{}(hash_string); } bool compare_cell_parameters_and_connections(const RTLIL::Cell *cell1, const RTLIL::Cell *cell2) @@ -268,13 +267,13 @@ struct OptMergeWorker } did_something = false; - dict sharemap; + std::unordered_map sharemap; for (auto cell : cells) { if ((!mode_share_all && !ct.cell_known(cell->type)) || !cell->known()) continue; - auto hash = hash_cell_parameters_and_connections(cell); + FingerPrint hash = hash_cell_parameters_and_connections(cell); auto r = sharemap.insert(std::make_pair(hash, cell)); if (!r.second) { if (compare_cell_parameters_and_connections(cell, r.first->second)) { From 058973faee14b822d4b68444b0cc09eea099f6f1 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 2 Oct 2023 16:15:47 -0700 Subject: [PATCH 089/173] Undo formatting change. --- kernel/rtlil.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index f53d9df8c84..ef33ab2d728 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -308,7 +308,7 @@ namespace RTLIL bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; } char operator[](size_t i) const { - const char *p = c_str(); + const char *p = c_str(); #ifndef NDEBUG for (; i != 0; i--, p++) log_assert(*p != 0); From 11ffd7df40260f782c82b43be190a48ec88214a1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 00:15:18 +0000 Subject: [PATCH 090/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a96f3f54919..ce76fda9ac2 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+79 +YOSYS_VER := 0.33+103 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 4968229efc2918365b2da0493fd33b6c57f09380 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 2 Oct 2023 11:00:00 -0700 Subject: [PATCH 091/173] Speed up stringf / vstringf by 1.8x. The main speedup is accomplished by avoiding a heap allocation in the common case where the final string length is less than 128. Inlining stringf & vstringf adds an additional improvement. --- kernel/yosys.cc | 46 +++--------------------------------- kernel/yosys.h | 63 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 45 deletions(-) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index bd8dded4b5f..82f1a9dd9f7 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -74,6 +74,7 @@ #include #include "libs/json11/json11.hpp" +#include "devtools/build/runtime/get_runfiles_dir.h" YOSYS_NAMESPACE_BEGIN @@ -175,48 +176,6 @@ int ceil_log2(int x) #endif } -std::string stringf(const char *fmt, ...) -{ - std::string string; - va_list ap; - - va_start(ap, fmt); - string = vstringf(fmt, ap); - va_end(ap); - - return string; -} - -std::string vstringf(const char *fmt, va_list ap) -{ - std::string string; - char *str = NULL; - -#if defined(_WIN32 )|| defined(__CYGWIN__) - int sz = 64, rc; - while (1) { - va_list apc; - va_copy(apc, ap); - str = (char*)realloc(str, sz); - rc = vsnprintf(str, sz, fmt, apc); - va_end(apc); - if (rc >= 0 && rc < sz) - break; - sz *= 2; - } -#else - if (vasprintf(&str, fmt, ap) < 0) - str = NULL; -#endif - - if (str != NULL) { - string = str; - free(str); - } - - return string; -} - int readsome(std::istream &f, char *s, int n) { int rc = int(f.readsome(s, n)); @@ -1025,7 +984,8 @@ void init_share_dirname() return; } # ifdef YOSYS_DATDIR - proc_share_path = YOSYS_DATDIR "/"; + proc_share_path = devtools_build::GetRunfilesDir() + "/"; + proc_share_path += YOSYS_DATDIR "/"; if (check_file_exists(proc_share_path, true)) { yosys_share_dirname = proc_share_path; return; diff --git a/kernel/yosys.h b/kernel/yosys.h index 29415ff842e..57deb72365e 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -272,8 +272,62 @@ inline void memhasher() { if (memhasher_active) memhasher_do(); } void yosys_banner(); int ceil_log2(int x) YS_ATTRIBUTE(const); -std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)); -std::string vstringf(const char *fmt, va_list ap); + +inline std::string vstringf(const char *fmt, va_list ap) +{ + // For the common case of strings shorter than 128 (including the trailing + // '\0'), save a heap allocation by using a stack allocated buffer. + const int kBufSize = 128; + char buf[kBufSize]; + buf[0] = '\0'; + va_list apc; + va_copy(apc, ap); + int n = vsnprintf(buf, kBufSize, fmt, apc); + va_end(apc); + if (n < kBufSize) + return std::string(buf); + + std::string string; + char *str = NULL; +#if defined(_WIN32 )|| defined(__CYGWIN__) + int sz = 2 * kBufSize, rc; + while (1) { + va_copy(apc, ap); + str = (char*)realloc(str, sz); + rc = vsnprintf(str, sz, fmt, apc); + va_end(apc); + if (rc >= 0 && rc < sz) + break; + sz *= 2; + } + if (str != NULL) { + string = str; + free(str); + } + return string; +#else + if (vasprintf(&str, fmt, ap) < 0) + str = NULL; + if (str != NULL) { + string = str; + free(str); + } + return string; +#endif +} + +inline std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)) +{ + std::string string; + va_list ap; + + va_start(ap, fmt); + string = vstringf(fmt, ap); + va_end(ap); + + return string; +} + int readsome(std::istream &f, char *s, int n); std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false); std::vector split_tokens(const std::string &text, const char *sep = " \t\r\n"); @@ -289,6 +343,11 @@ bool is_absolute_path(std::string filename); void remove_directory(std::string dirname); std::string escape_filename_spaces(const std::string& filename); +using ys_size_type = int64_t; // Large enough to deal with large number of data, but also not experiencing unsigned overflow. + +// TODO(hzeller): these need to return ys_size_type, but in the course of +// refactoring, each type will be handled separately (and gets their own GetSize() function). After all +// size types are converted, this template can be changed to return ys_size_type. template int GetSize(const T &obj) { return obj.size(); } inline int GetSize(RTLIL::Wire *wire); From ff915d21b67b2746573372568c51e5737b356083 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 2 Oct 2023 11:05:04 -0700 Subject: [PATCH 092/173] Update comment. --- kernel/yosys.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/yosys.h b/kernel/yosys.h index 57deb72365e..5ee5eb75f30 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -275,8 +275,8 @@ int ceil_log2(int x) YS_ATTRIBUTE(const); inline std::string vstringf(const char *fmt, va_list ap) { - // For the common case of strings shorter than 128 (including the trailing - // '\0'), save a heap allocation by using a stack allocated buffer. + // For the common case of strings shorter than 128, save a heap + // allocation by using a stack allocated buffer. const int kBufSize = 128; char buf[kBufSize]; buf[0] = '\0'; From cb9f318d37bdb557b7111914e8c25b3ed505ac3d Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 2 Oct 2023 11:07:28 -0700 Subject: [PATCH 093/173] Remove local modifications. --- kernel/yosys.cc | 4 +--- kernel/yosys.h | 5 ----- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 82f1a9dd9f7..559ce872cad 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -74,7 +74,6 @@ #include #include "libs/json11/json11.hpp" -#include "devtools/build/runtime/get_runfiles_dir.h" YOSYS_NAMESPACE_BEGIN @@ -984,8 +983,7 @@ void init_share_dirname() return; } # ifdef YOSYS_DATDIR - proc_share_path = devtools_build::GetRunfilesDir() + "/"; - proc_share_path += YOSYS_DATDIR "/"; + proc_share_path = YOSYS_DATDIR "/"; if (check_file_exists(proc_share_path, true)) { yosys_share_dirname = proc_share_path; return; diff --git a/kernel/yosys.h b/kernel/yosys.h index 5ee5eb75f30..99edfb70036 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -343,11 +343,6 @@ bool is_absolute_path(std::string filename); void remove_directory(std::string dirname); std::string escape_filename_spaces(const std::string& filename); -using ys_size_type = int64_t; // Large enough to deal with large number of data, but also not experiencing unsigned overflow. - -// TODO(hzeller): these need to return ys_size_type, but in the course of -// refactoring, each type will be handled separately (and gets their own GetSize() function). After all -// size types are converted, this template can be changed to return ys_size_type. template int GetSize(const T &obj) { return obj.size(); } inline int GetSize(RTLIL::Wire *wire); From a6247cba42d126fe429dba37c62145b24ac8f500 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 2 Oct 2023 11:24:53 -0700 Subject: [PATCH 094/173] Fix compiler warnings from GCC. --- kernel/yosys.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/yosys.h b/kernel/yosys.h index 99edfb70036..97a79861e15 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -316,7 +316,9 @@ inline std::string vstringf(const char *fmt, va_list ap) #endif } -inline std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)) +std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)); + +inline std::string stringf(const char *fmt, ...) { std::string string; va_list ap; From c1745970147bb17d65943297c8b9369cacec2bd3 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 3 Oct 2023 11:46:43 +0200 Subject: [PATCH 095/173] Fix sva_value_change_changed test for updated verific --- tests/sva/sva_value_change_changed.sv | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/sva/sva_value_change_changed.sv b/tests/sva/sva_value_change_changed.sv index 8f3a05a2f2e..3ce2078500c 100644 --- a/tests/sva/sva_value_change_changed.sv +++ b/tests/sva/sva_value_change_changed.sv @@ -8,9 +8,11 @@ module top ( $changed(b) ); + wire x = 'x; + `ifndef FAIL assume property ( - b !== 'x ##1 $changed(b) + b !== x ##1 $changed(b) ); `endif From 563a56d9ff07cadd93b8b64977d1b8b83f94170d Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 3 Oct 2023 15:52:01 +0200 Subject: [PATCH 096/173] verific: Improve interaction between -L, -work and bind statements --- frontends/verific/verific.cc | 40 +++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 310e3918015..9138bb63c03 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -3063,6 +3063,7 @@ struct VerificPass : public Pass { int argidx = 1; std::string work = "work"; bool is_work_set = false; + (void)is_work_set; veri_file::RegisterCallBackVerificStream(&verific_read_cb); if (GetSize(args) > argidx && (args[argidx] == "-set-error" || args[argidx] == "-set-warning" || @@ -3140,7 +3141,20 @@ struct VerificPass : public Pass { } veri_file::RemoveAllLOptions(); - veri_file::AddLOption("work"); + for (int i = argidx; i < GetSize(args); i++) + { + if (args[i] == "-work" && i+1 < GetSize(args)) { + work = args[++i]; + is_work_set = true; + continue; + } + if (args[i] == "-L" && i+1 < GetSize(args)) { + ++i; + continue; + } + break; + } + veri_file::AddLOption(work.c_str()); for (int i = argidx; i < GetSize(args); i++) { if (args[i] == "-work" && i+1 < GetSize(args)) { @@ -3148,7 +3162,7 @@ struct VerificPass : public Pass { continue; } if (args[i] == "-L" && i+1 < GetSize(args)) { - if (args[++i] == "work") + if (args[++i] == work) veri_file::RemoveAllLOptions(); continue; } @@ -3641,7 +3655,7 @@ struct VerificPass : public Pass { if (module_name && module_name->IsHierName()) { VeriName *prefix = module_name->GetPrefix() ; const char *lib_name = (prefix) ? prefix->GetName() : 0 ; - if (!Strings::compare("work", lib_name)) lib = veri_file::GetLibrary(lib_name, 1) ; + if (work != lib_name) lib = veri_file::GetLibrary(lib_name, 1) ; } if (lib && module_name) top_mod_names.insert(lib->GetModule(module_name->GetName(), 1)->GetName()); @@ -3663,13 +3677,19 @@ struct VerificPass : public Pass { log_error("Can't find module/unit '%s'.\n", name); } - if (veri_lib) { - // Also elaborate all root modules since they may contain bind statements - MapIter mi; - VeriModule *veri_module; - FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { - if (!veri_module->IsRootModule()) continue; - veri_modules.InsertLast(veri_module); + + const char *lib_name = nullptr; + SetIter si; + FOREACH_SET_ITEM(veri_file::GetAllLOptions(), si, &lib_name) { + VeriLibrary* veri_lib = veri_file::GetLibrary(lib_name, 0); + if (veri_lib) { + // Also elaborate all root modules since they may contain bind statements + MapIter mi; + VeriModule *veri_module; + FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { + if (!veri_module->IsRootModule()) continue; + veri_modules.InsertLast(veri_module); + } } } From 7b454d4633c12dd7ee55f52911116524a3a6da41 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Tue, 3 Oct 2023 14:06:41 -0700 Subject: [PATCH 097/173] Revert changes to celltypes.h. --- kernel/celltypes.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 58c6907dc63..cad505d9afd 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -56,7 +56,7 @@ struct CellTypes setup_stdcells_mem(); } - void setup_type(const RTLIL::IdString& type, const pool &inputs, const pool &outputs, bool is_evaluable = false) + void setup_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, bool is_evaluable = false) { CellType ct = {type, inputs, outputs, is_evaluable}; cell_types[ct.type] = ct; @@ -298,24 +298,24 @@ struct CellTypes cell_types.clear(); } - bool cell_known(const RTLIL::IdString& type) const + bool cell_known(RTLIL::IdString type) const { return cell_types.count(type) != 0; } - bool cell_output(const RTLIL::IdString& type, const RTLIL::IdString& port) const + bool cell_output(RTLIL::IdString type, RTLIL::IdString port) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.outputs.count(port) != 0; } - bool cell_input(const RTLIL::IdString& type, const RTLIL::IdString& port) const + bool cell_input(RTLIL::IdString type, RTLIL::IdString port) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.inputs.count(port) != 0; } - bool cell_evaluable(const RTLIL::IdString& type) const + bool cell_evaluable(RTLIL::IdString type) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.is_evaluable; From 8e0308b5e7b0c0bbe10c072123d2e7b945f4b6b0 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Tue, 3 Oct 2023 14:25:59 -0700 Subject: [PATCH 098/173] Revert changes to celltypes.h. Use dict instead of std::unordered_map and most hash function for uint64_t to hashlib.h to support this. --- kernel/hashlib.h | 6 ++++++ passes/opt/opt_merge.cc | 2 +- passes/sat/recover_names.cc | 9 +-------- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index be759fdf0a4..9cf43da6ca5 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -90,6 +90,12 @@ template<> struct hash_ops : hash_int_ops return a; } }; +template<> struct hash_ops : hash_int_ops +{ + static inline unsigned int hash(uint64_t a) { + return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); + } +}; template<> struct hash_ops { static inline bool cmp(const std::string &a, const std::string &b) { diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index 4bcd5a18947..87ad01f00ec 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -267,7 +267,7 @@ struct OptMergeWorker } did_something = false; - std::unordered_map sharemap; + dict sharemap; for (auto cell : cells) { if ((!mode_share_all && !ct.cell_known(cell->type)) || !cell->known()) diff --git a/passes/sat/recover_names.cc b/passes/sat/recover_names.cc index 2d7e7f01cfa..4c30a363202 100644 --- a/passes/sat/recover_names.cc +++ b/passes/sat/recover_names.cc @@ -29,13 +29,6 @@ USING_YOSYS_NAMESPACE -template<> struct hashlib::hash_ops : hashlib::hash_int_ops -{ - static inline unsigned int hash(uint64_t a) { - return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); - } -}; - PRIVATE_NAMESPACE_BEGIN // xorshift128 params @@ -453,7 +446,7 @@ struct RecoverNamesWorker { pool comb_whiteboxes, buffer_types; // class -> (gold, (gate, inverted)) - dict, dict>> cls2bits; + dict, dict>> cls2bits; void analyse_boxes() { From 57a2b4b0cd542f2053616bbc8ece614a28d72f3a Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Tue, 3 Oct 2023 15:02:02 -0700 Subject: [PATCH 099/173] Explicitly use uint64_t as the type of fingerprint to avoid type mismatch with some compilers. --- passes/opt/opt_merge.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index 87ad01f00ec..248ba80913b 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -41,7 +41,6 @@ struct OptMergeWorker CellTypes ct; int total_count; - using FingerPrint = std::hash::result_type; static void sort_pmux_conn(dict &conn) { @@ -78,7 +77,7 @@ struct OptMergeWorker return str; } - FingerPrint hash_cell_parameters_and_connections(const RTLIL::Cell *cell) + uint64_t hash_cell_parameters_and_connections(const RTLIL::Cell *cell) { vector hash_conn_strings; std::string hash_string = cell->type.str() + "\n"; @@ -267,13 +266,13 @@ struct OptMergeWorker } did_something = false; - dict sharemap; + dict sharemap; for (auto cell : cells) { if ((!mode_share_all && !ct.cell_known(cell->type)) || !cell->known()) continue; - FingerPrint hash = hash_cell_parameters_and_connections(cell); + uint64_t hash = hash_cell_parameters_and_connections(cell); auto r = sharemap.insert(std::make_pair(hash, cell)); if (!r.second) { if (compare_cell_parameters_and_connections(cell, r.first->second)) { From 294844137bb1fd8854a18cc2a0c703aa30726761 Mon Sep 17 00:00:00 2001 From: Lofty Date: Tue, 3 Oct 2023 10:32:18 +0100 Subject: [PATCH 100/173] gowin: fix abc9 attributes and specify blocks --- techlibs/gowin/cells_sim.v | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/techlibs/gowin/cells_sim.v b/techlibs/gowin/cells_sim.v index 86bd677e229..b268690803f 100644 --- a/techlibs/gowin/cells_sim.v +++ b/techlibs/gowin/cells_sim.v @@ -197,7 +197,7 @@ module DFFE (output reg Q, input D, CLK, CE); end endmodule // DFFE (positive clock edge; clock enable) -(* abc9_box, lib_whitebox *) +(* abc9_flop, lib_whitebox *) module DFFS (output reg Q, input D, CLK, SET); parameter [0:0] INIT = 1'b1; initial Q = INIT; @@ -216,7 +216,7 @@ module DFFS (output reg Q, input D, CLK, SET); end endmodule // DFFS (positive clock edge; synchronous set) -(* abc9_box, lib_whitebox *) +(* abc9_flop, lib_whitebox *) module DFFSE (output reg Q, input D, CLK, CE, SET); parameter [0:0] INIT = 1'b1; initial Q = INIT; @@ -282,7 +282,7 @@ module DFFP (output reg Q, input D, CLK, PRESET); specify (posedge CLK => (Q : D)) = (480, 660); - (posedge PRESET => (Q : 1'b1)) = (1800, 2679); + (PRESET => Q) = (1800, 2679); $setup(D, posedge CLK, 576); endspecify @@ -301,7 +301,7 @@ module DFFPE (output reg Q, input D, CLK, CE, PRESET); specify if (CE) (posedge CLK => (Q : D)) = (480, 660); - (posedge PRESET => (Q : 1'b1)) = (1800, 2679); + (PRESET => Q) = (1800, 2679); $setup(D, posedge CLK &&& CE, 576); $setup(CE, posedge CLK, 63); endspecify @@ -321,7 +321,7 @@ module DFFC (output reg Q, input D, CLK, CLEAR); specify (posedge CLK => (Q : D)) = (480, 660); - (posedge CLEAR => (Q : 1'b0)) = (1800, 2679); + (CLEAR => Q) = (1800, 2679); $setup(D, posedge CLK, 576); endspecify @@ -340,7 +340,7 @@ module DFFCE (output reg Q, input D, CLK, CE, CLEAR); specify if (CE) (posedge CLK => (Q : D)) = (480, 660); - (posedge CLEAR => (Q : 1'b0)) = (1800, 2679); + (CLEAR => Q) = (1800, 2679); $setup(D, posedge CLK &&& CE, 576); $setup(CE, posedge CLK, 63); endspecify @@ -384,7 +384,7 @@ module DFFNE (output reg Q, input D, CLK, CE); end endmodule // DFFNE (negative clock edge; clock enable) -(* abc9_box, lib_whitebox *) +(* abc9_flop, lib_whitebox *) module DFFNS (output reg Q, input D, CLK, SET); parameter [0:0] INIT = 1'b1; initial Q = INIT; @@ -403,7 +403,7 @@ module DFFNS (output reg Q, input D, CLK, SET); end endmodule // DFFNS (negative clock edge; synchronous set) -(* abc9_box, lib_whitebox *) +(* abc9_flop, lib_whitebox *) module DFFNSE (output reg Q, input D, CLK, CE, SET); parameter [0:0] INIT = 1'b1; initial Q = INIT; @@ -469,7 +469,7 @@ module DFFNP (output reg Q, input D, CLK, PRESET); specify (negedge CLK => (Q : D)) = (480, 660); - (posedge PRESET => (Q : 1'b1)) = (1800, 2679); + (PRESET => Q) = (1800, 2679); $setup(D, negedge CLK, 576); endspecify @@ -488,7 +488,7 @@ module DFFNPE (output reg Q, input D, CLK, CE, PRESET); specify if (CE) (negedge CLK => (Q : D)) = (480, 660); - (posedge PRESET => (Q : 1'b1)) = (1800, 2679); + (PRESET => Q) = (1800, 2679); $setup(D, negedge CLK &&& CE, 576); $setup(CE, negedge CLK, 63); endspecify @@ -508,7 +508,7 @@ module DFFNC (output reg Q, input D, CLK, CLEAR); specify (negedge CLK => (Q : D)) = (480, 660); - (posedge CLEAR => (Q : 1'b0)) = (1800, 2679); + (CLEAR => Q) = (1800, 2679); $setup(D, negedge CLK, 576); endspecify @@ -527,7 +527,7 @@ module DFFNCE (output reg Q, input D, CLK, CE, CLEAR); specify if (CE) (negedge CLK => (Q : D)) = (480, 660); - (posedge CLEAR => (Q : 1'b0)) = (1800, 2679); + (CLEAR => Q) = (1800, 2679); $setup(D, negedge CLK &&& CE, 576); $setup(CE, negedge CLK, 63); endspecify @@ -957,7 +957,7 @@ end endmodule - +(* abc9_flop, lib_whitebox *) module RAM16S1 (DO, DI, AD, WRE, CLK); parameter INIT_0 = 16'h0000; @@ -992,7 +992,7 @@ end endmodule - +(* abc9_flop, lib_whitebox *) module RAM16S2 (DO, DI, AD, WRE, CLK); parameter INIT_0 = 16'h0000; @@ -1031,7 +1031,7 @@ end endmodule - +(* abc9_flop, lib_whitebox *) module RAM16S4 (DO, DI, AD, WRE, CLK); parameter INIT_0 = 16'h0000; From f00d6f3c12071c741abe6248ff03a026f6509dae Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 4 Oct 2023 00:15:12 +0000 Subject: [PATCH 101/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ce76fda9ac2..92b0a5d2e4e 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+103 +YOSYS_VER := 0.33+112 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 0434f9d3d1decc563877f73a3b963bc3d0cdef6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 4 Oct 2023 23:21:40 +0200 Subject: [PATCH 102/173] booth: Fix vacancy check when summing down result In commit fedd12261 ("booth: Move away from explicit `Wire` pointers") a bug was introduced when checking for vacant slots in arrays holding some intermediate results. Non-wire SigBit values were taken to imply a vacant slot, but actually a constant one can make its way into those results, if the multiplier cell configuration is just right. Fix the vacancy check to address the bug. --- passes/techmap/booth.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index 000dcff14ec..e1e6b360ab6 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -533,7 +533,7 @@ struct BoothPassWorker { // get the bits in this column. SigSpec column_bits; for (int row_ix = 0; row_ix < row_size; row_ix++) { - if (bits_to_reduce[row_ix][column_ix].wire) + if (bits_to_reduce[row_ix][column_ix] != State::S0) column_bits.append(bits_to_reduce[row_ix][column_ix]); } for (auto c : carry_bits_to_add_to_next_column) { @@ -750,7 +750,7 @@ struct BoothPassWorker { SigSpec first_csa_ips; // get the first 3 inputs, if possible for (var_ix = 0; var_ix < column_bits.size() && first_csa_ips.size() != 3; var_ix++) { - if (column_bits[var_ix].is_wire()) + if (column_bits[var_ix] != State::S0) first_csa_ips.append(column_bits[var_ix]); } @@ -782,7 +782,7 @@ struct BoothPassWorker { // get the next two variables to sum for (; var_ix <= column_bits.size() - 1 && csa_ips.size() < 2;) { // skip any empty bits - if (column_bits[var_ix].is_wire()) + if (column_bits[var_ix] != State::S0) csa_ips.append(column_bits[var_ix]); var_ix++; } From 4506e11d0fd1cd05a795203dc95a39f921c492b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 4 Oct 2023 23:29:40 +0200 Subject: [PATCH 103/173] booth: Extend test to catch bug from previous commit --- tests/techmap/booth.ys | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/techmap/booth.ys b/tests/techmap/booth.ys index ab7efc7b7fd..55dfdb8e9cd 100644 --- a/tests/techmap/booth.ys +++ b/tests/techmap/booth.ys @@ -1 +1,15 @@ -test_cell -s 1694091355 -n 100 -script booth_map_script.ys_ $mul +read_verilog < Date: Thu, 5 Oct 2023 09:14:12 +0200 Subject: [PATCH 104/173] Release version 0.34 --- CHANGELOG | 19 ++++++++++++++++++- Makefile | 4 ++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a662ba4dad3..60ad78b7265 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,13 +2,30 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.33 .. Yosys 0.34-dev +Yosys 0.33 .. Yosys 0.34 -------------------------- + * New commands and options + - Added option "-assert" to "sim" pass. + - Added option "-noinitstate" to "sim" pass. + - Added option "-dont_use" to "abc" pass. + - Added "dft_tag" pass to create tagging logic for data flow tracking. + - Added "future" pass to resolve future sampled value functions. + - Added "booth" pass to map $mul cells to Booth multipliers. + - Added option "-booth" to "synth" pass. * SystemVerilog - Added support for assignments within expressions, e.g., `x[y++] = z;` or `x = (y *= 2) - 1;`. + * Verific support + - "src" attribute contain full location info. + - module parameters are kept after import. + - accurate access order semantics in memory inference. + - better "bind" support for mixed language projects. + + * Various + - "show" command displays dot instead of box for wire aliases. + Yosys 0.32 .. Yosys 0.33 -------------------------- * Various diff --git a/Makefile b/Makefile index 92b0a5d2e4e..b9c10898150 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+112 +YOSYS_VER := 0.34 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -157,7 +157,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 2584903.. | wc -l`/;" Makefile +# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 2584903.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # From b88f7fc6e899ebed361b71efe12d095a8eeb61d2 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 5 Oct 2023 09:16:05 +0200 Subject: [PATCH 105/173] Next dev cycle --- CHANGELOG | 3 +++ Makefile | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 60ad78b7265..ee5f6b43d25 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,9 @@ List of major changes and improvements between releases ======================================================= +Yosys 0.34 .. Yosys 0.35-dev +-------------------------- + Yosys 0.33 .. Yosys 0.34 -------------------------- * New commands and options diff --git a/Makefile b/Makefile index b9c10898150..650e553c932 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34 +YOSYS_VER := 0.34+0 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -157,7 +157,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: -# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 2584903.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 4a1b559.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # From 824fdaadf62fa58b81d268340a56bf847dc5724b Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 5 Oct 2023 09:55:53 +0200 Subject: [PATCH 106/173] mingw build fix --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 650e553c932..688b5939ded 100644 --- a/Makefile +++ b/Makefile @@ -357,7 +357,7 @@ CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s LDLIBS := $(filter-out -lrt,$(LDLIBS)) ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="-lpthread -s" ABC_USE_NO_READLINE=0 CC="i686-w64-mingw32-gcc" CXX="$(CXX)" +ABCMKARGS += LIBS="-lpthread -lshlwapi -s" ABC_USE_NO_READLINE=0 CC="i686-w64-mingw32-gcc" CXX="$(CXX)" EXE = .exe else ifeq ($(CONFIG),msys2-64) @@ -368,7 +368,7 @@ CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s LDLIBS := $(filter-out -lrt,$(LDLIBS)) ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="-lpthread -s" ABC_USE_NO_READLINE=0 CC="x86_64-w64-mingw32-gcc" CXX="$(CXX)" +ABCMKARGS += LIBS="-lpthread -lshlwapi -s" ABC_USE_NO_READLINE=0 CC="x86_64-w64-mingw32-gcc" CXX="$(CXX)" EXE = .exe else ifneq ($(CONFIG),none) From 268fe92d22536525b3c88b1dc14fff2e4a319294 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 5 Oct 2023 11:22:40 +0200 Subject: [PATCH 107/173] verific: save original module name --- frontends/verific/verific.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 9138bb63c03..85a685376ef 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1275,6 +1275,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma log("Importing module %s.\n", RTLIL::id2cstr(module->name)); } import_attributes(module->attributes, nl, nl); + module->set_string_attribute(ID::hdlname, nl->CellBaseName()); const char *param_name ; const char *param_value ; MapIter mi; From 23b9e61c477277b00cf34e593b8979f8f15a3600 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Thu, 5 Oct 2023 16:28:17 +0200 Subject: [PATCH 108/173] verific: Pass list of top modules to static elaboration --- frontends/verific/verific.cc | 139 ++++++++++++++++++++--------------- 1 file changed, 80 insertions(+), 59 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 9138bb63c03..da449e2d718 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -3595,15 +3595,16 @@ struct VerificPass : public Pass { std::set top_mod_names; + if (mode_all) + { + #ifdef YOSYSHQ_VERIFIC_EXTENSIONS - VerificExtensions::ElaborateAndRewrite(work, ¶meters); - verific_error_msg.clear(); + VerificExtensions::ElaborateAndRewrite(work, ¶meters); + verific_error_msg.clear(); #endif - if (!ppfile.empty()) - veri_file::PrettyPrint(ppfile.c_str(), nullptr, work.c_str()); + if (!ppfile.empty()) + veri_file::PrettyPrint(ppfile.c_str(), nullptr, work.c_str()); - if (mode_all) - { log("Running hier_tree::ElaborateAll().\n"); VeriLibrary *veri_lib = veri_file::GetLibrary(work.c_str(), 1); @@ -3628,73 +3629,93 @@ struct VerificPass : public Pass { if (argidx == GetSize(args)) cmd_error(args, argidx, "No top module specified.\n"); - VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1); + Array *netlists = nullptr; + +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + for (int static_elaborate = 1; static_elaborate >= 0; static_elaborate--) +#endif + { + + VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1); #ifdef VERIFIC_VHDL_SUPPORT - VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); + VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); #endif - Array veri_modules, vhdl_units; - for (; argidx < GetSize(args); argidx++) - { - const char *name = args[argidx].c_str(); - top_mod_names.insert(name); - - VeriModule *veri_module = veri_lib ? veri_lib->GetModule(name, 1) : nullptr; - if (veri_module) { - if (veri_module->IsConfiguration()) { - log("Adding Verilog configuration '%s' to elaboration queue.\n", name); - veri_modules.InsertLast(veri_module); - - top_mod_names.erase(name); - - VeriConfiguration *cfg = (VeriConfiguration*)veri_module; - VeriName *module_name; - int i; - FOREACH_ARRAY_ITEM(cfg->GetTopModuleNames(), i, module_name) { - VeriLibrary *lib = veri_module->GetLibrary() ; - if (module_name && module_name->IsHierName()) { - VeriName *prefix = module_name->GetPrefix() ; - const char *lib_name = (prefix) ? prefix->GetName() : 0 ; - if (work != lib_name) lib = veri_file::GetLibrary(lib_name, 1) ; + Array veri_modules, vhdl_units; + for (int i = argidx; i < GetSize(args); i++) + { + const char *name = args[i].c_str(); + top_mod_names.insert(name); + + VeriModule *veri_module = veri_lib ? veri_lib->GetModule(name, 1) : nullptr; + if (veri_module) { + if (veri_module->IsConfiguration()) { + log("Adding Verilog configuration '%s' to elaboration queue.\n", name); + veri_modules.InsertLast(veri_module); + + top_mod_names.erase(name); + + VeriConfiguration *cfg = (VeriConfiguration*)veri_module; + VeriName *module_name; + int i; + FOREACH_ARRAY_ITEM(cfg->GetTopModuleNames(), i, module_name) { + VeriLibrary *lib = veri_module->GetLibrary() ; + if (module_name && module_name->IsHierName()) { + VeriName *prefix = module_name->GetPrefix() ; + const char *lib_name = (prefix) ? prefix->GetName() : 0 ; + if (work != lib_name) lib = veri_file::GetLibrary(lib_name, 1) ; + } + if (lib && module_name) + top_mod_names.insert(lib->GetModule(module_name->GetName(), 1)->GetName()); } - if (lib && module_name) - top_mod_names.insert(lib->GetModule(module_name->GetName(), 1)->GetName()); + } else { + log("Adding Verilog module '%s' to elaboration queue.\n", name); + veri_modules.InsertLast(veri_module); } - } else { - log("Adding Verilog module '%s' to elaboration queue.\n", name); - veri_modules.InsertLast(veri_module); + continue; } - continue; - } #ifdef VERIFIC_VHDL_SUPPORT - VhdlDesignUnit *vhdl_unit = vhdl_lib ? vhdl_lib->GetPrimUnit(name) : nullptr; - if (vhdl_unit) { - log("Adding VHDL unit '%s' to elaboration queue.\n", name); - vhdl_units.InsertLast(vhdl_unit); - continue; - } + VhdlDesignUnit *vhdl_unit = vhdl_lib ? vhdl_lib->GetPrimUnit(name) : nullptr; + if (vhdl_unit) { + log("Adding VHDL unit '%s' to elaboration queue.\n", name); + vhdl_units.InsertLast(vhdl_unit); + continue; + } #endif - log_error("Can't find module/unit '%s'.\n", name); - } + log_error("Can't find module/unit '%s'.\n", name); + } +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + if (static_elaborate) { + VerificExtensions::ElaborateAndRewrite(work, &veri_modules, &vhdl_units, ¶meters); + verific_error_msg.clear(); +#endif + if (!ppfile.empty()) + veri_file::PrettyPrint(ppfile.c_str(), nullptr, work.c_str()); - const char *lib_name = nullptr; - SetIter si; - FOREACH_SET_ITEM(veri_file::GetAllLOptions(), si, &lib_name) { - VeriLibrary* veri_lib = veri_file::GetLibrary(lib_name, 0); - if (veri_lib) { - // Also elaborate all root modules since they may contain bind statements - MapIter mi; - VeriModule *veri_module; - FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { - if (!veri_module->IsRootModule()) continue; - veri_modules.InsertLast(veri_module); +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + continue; + } +#endif + const char *lib_name = nullptr; + SetIter si; + FOREACH_SET_ITEM(veri_file::GetAllLOptions(), si, &lib_name) { + VeriLibrary* veri_lib = veri_file::GetLibrary(lib_name, 0); + if (veri_lib) { + // Also elaborate all root modules since they may contain bind statements + MapIter mi; + VeriModule *veri_module; + FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { + if (!veri_module->IsRootModule()) continue; + veri_modules.InsertLast(veri_module); + } } } + + log("Running hier_tree::Elaborate().\n"); + netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, ¶meters); } - log("Running hier_tree::Elaborate().\n"); - Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, ¶meters); Netlist *nl; int i; From 47a4b790f8162451d91cf8a04f23f2893e0a3824 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Thu, 5 Oct 2023 16:40:43 +0200 Subject: [PATCH 109/173] verific: Pass top modules to static elaboration when using hierarchy --- frontends/verific/verific.cc | 86 ++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index da449e2d718..62307a45961 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2495,51 +2495,71 @@ std::string verific_import(Design *design, const std::mapGetModule(top.c_str(), 1); - if (veri_module) { - veri_modules.InsertLast(veri_module); - if (veri_module->IsConfiguration()) { - VeriConfiguration *cfg = (VeriConfiguration*)veri_module; - VeriName *module_name = (VeriName*)cfg->GetTopModuleNames()->GetLast(); - VeriLibrary *lib = veri_module->GetLibrary() ; - if (module_name && module_name->IsHierName()) { - VeriName *prefix = module_name->GetPrefix() ; - const char *lib_name = (prefix) ? prefix->GetName() : 0 ; - if (!Strings::compare("work", lib_name)) lib = veri_file::GetLibrary(lib_name, 1) ; + +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + for (int static_elaborate = 1; static_elaborate >= 0; static_elaborate--) +#endif + { + Array veri_modules, vhdl_units; + + if (veri_lib) { + VeriModule *veri_module = veri_lib->GetModule(top.c_str(), 1); + if (veri_module) { + veri_modules.InsertLast(veri_module); + if (veri_module->IsConfiguration()) { + VeriConfiguration *cfg = (VeriConfiguration*)veri_module; + VeriName *module_name = (VeriName*)cfg->GetTopModuleNames()->GetLast(); + VeriLibrary *lib = veri_module->GetLibrary() ; + if (module_name && module_name->IsHierName()) { + VeriName *prefix = module_name->GetPrefix() ; + const char *lib_name = (prefix) ? prefix->GetName() : 0 ; + if (!Strings::compare("work", lib_name)) lib = veri_file::GetLibrary(lib_name, 1) ; + } + if (lib && module_name) + top = lib->GetModule(module_name->GetName(), 1)->GetName(); } - if (lib && module_name) - top = lib->GetModule(module_name->GetName(), 1)->GetName(); } - } - // Also elaborate all root modules since they may contain bind statements - MapIter mi; - FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { - if (!veri_module->IsRootModule()) continue; - veri_modules.InsertLast(veri_module); +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + if (!static_elaborate) +#endif + { + // Also elaborate all root modules since they may contain bind statements + MapIter mi; + FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { + if (!veri_module->IsRootModule()) continue; + veri_modules.InsertLast(veri_module); + } + } } - } #ifdef VERIFIC_VHDL_SUPPORT - if (vhdl_lib) { - VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(top.c_str()); - if (vhdl_unit) - vhdl_units.InsertLast(vhdl_unit); - } + if (vhdl_lib) { + VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(top.c_str()); + if (vhdl_unit) + vhdl_units.InsertLast(vhdl_unit); + } #endif - netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &verific_params); + +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + if (static_elaborate) { + VerificExtensions::ElaborateAndRewrite("work", &veri_modules, &vhdl_units, &verific_params); + verific_error_msg.clear(); + continue; + } +#endif + + netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &verific_params); + } } Netlist *nl; From 6ac43e49bc7db6a6c13b0ff302ef193db1fa7064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 5 Oct 2023 19:21:52 +0200 Subject: [PATCH 110/173] sim: Change clocked read port suggestion to `memory_nordff` `memory_nordff` has the advantage that it can be called just ahead of the simulation step no matter whether the clocked read port has been inferred or was explicitly instantiated in a flow. --- passes/sat/sim.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 963c6481b16..31490591474 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -579,7 +579,7 @@ struct SimInstance Const data = Const(State::Sx, mem.width << port.wide_log2); if (port.clk_enable) - log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module), log_id(mem.memid)); + log_error("Memory %s.%s has clocked read ports. Run 'memory_nordff' to transform the circuit to remove those.\n", log_id(module), log_id(mem.memid)); if (addr.is_fully_def()) { int addr_int = addr.as_int(); From a782b15aae8890c819c133566f77dc5ac8362b99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 5 Oct 2023 19:22:08 +0200 Subject: [PATCH 111/173] sim: s/instanced/instantiated/ --- passes/sat/sim.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 31490591474..9ce79973599 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -219,7 +219,7 @@ struct SimInstance log_assert(module); if (module->get_blackbox_attribute(true)) - log_error("Cannot simulate blackbox module %s (instanced at %s).\n", + log_error("Cannot simulate blackbox module %s (instantiated at %s).\n", log_id(module->name), hiername().c_str()); if (parent) { From c3fd88624a53c3778ea8ec1a43fc68d0686143ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 5 Oct 2023 19:23:48 +0200 Subject: [PATCH 112/173] sim: Bail on processes Instead of silently missimulating, error out when there are processes found in the simulation hierarchy. --- passes/sat/sim.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 9ce79973599..a8516470cfe 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -222,6 +222,10 @@ struct SimInstance log_error("Cannot simulate blackbox module %s (instantiated at %s).\n", log_id(module->name), hiername().c_str()); + if (module->has_processes()) + log_error("Found processes in simulation hierarchy (in module %s at %s). Run 'proc' first.\n", + log_id(module), hiername().c_str()); + if (parent) { log_assert(parent->children.count(instance) == 0); parent->children[instance] = this; From e38c9e01c901e0f5d0eb9fe18981a2c5c95ddf61 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Thu, 5 Oct 2023 15:24:26 -0700 Subject: [PATCH 113/173] Undo formatting changes in kernel/utils.h. --- kernel/utils.h | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/kernel/utils.h b/kernel/utils.h index 4679a23f2b9..9b64ed8e114 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -31,30 +31,34 @@ YOSYS_NAMESPACE_BEGIN // A map-like container, but you can save and restore the state // ------------------------------------------------ -template > struct stackmap { - private: - std::vector> backup_state; +template> +struct stackmap +{ +private: + std::vector> backup_state; dict current_state; static T empty_tuple; - public: - stackmap() {} - stackmap(const dict &other) : current_state(other) {} +public: + stackmap() { } + stackmap(const dict &other) : current_state(other) { } - template stackmap &operator=(const Other &other) + template + void operator=(const Other &other) { - for (const auto &it : current_state) + for (auto &it : current_state) if (!backup_state.empty() && backup_state.back().count(it.first) == 0) backup_state.back()[it.first] = new T(it.second); current_state.clear(); - for (const auto &it : other) + for (auto &it : other) set(it.first, it.second); - - return *this; } - bool has(const Key &k) { return current_state.count(k) != 0; } + bool has(const Key &k) + { + return current_state.count(k) != 0; + } void set(const Key &k, const T &v) { @@ -79,7 +83,7 @@ template > struct stackma void reset(const Key &k) { - for (int i = GetSize(backup_state) - 1; i >= 0; i--) + for (int i = GetSize(backup_state)-1; i >= 0; i--) if (backup_state[i].count(k) != 0) { if (backup_state[i].at(k) == nullptr) current_state.erase(k); @@ -90,14 +94,20 @@ template > struct stackma current_state.erase(k); } - const dict &stdmap() { return current_state; } + const dict &stdmap() + { + return current_state; + } - void save() { backup_state.resize(backup_state.size() + 1); } + void save() + { + backup_state.resize(backup_state.size()+1); + } void restore() { log_assert(!backup_state.empty()); - for (const auto &it : backup_state.back()) + for (auto &it : backup_state.back()) if (it.second != nullptr) { current_state[it.first] = *it.second; delete it.second; From fd7bd420b3d9f1b031adced3add1f15f29048906 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Thu, 5 Oct 2023 15:26:29 -0700 Subject: [PATCH 114/173] Add back newline. --- kernel/utils.h | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/utils.h b/kernel/utils.h index 9b64ed8e114..255f875c3f8 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -123,6 +123,7 @@ struct stackmap } }; + // ------------------------------------------------ // A simple class for topological sorting // ------------------------------------------------ From 0a37c2a301f3518df0d3a9ced7b2b9477b4fe9a0 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Thu, 5 Oct 2023 17:01:42 -0700 Subject: [PATCH 115/173] Fix translation bug: The old code really checks for the presense of a node, not an edge in glift and flatten. Add back statement that inserts nodes in order in opt_expr.cc. --- kernel/utils.h | 8 +------- passes/cmds/glift.cc | 2 +- passes/opt/opt_expr.cc | 1 + passes/techmap/flatten.cc | 2 +- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/kernel/utils.h b/kernel/utils.h index 255f875c3f8..5a1279ef01c 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -174,11 +174,7 @@ template , typename OPS = hash_ops> cla void edge(T left, T right) { edge(node(left), node(right)); } - bool has_edges(const T &node) - { - auto it = node_to_index.find(node); - return it == node_to_index.end() || !edges[it->second].empty(); - } + bool has_node(const T &node) { return node_to_index.find(node) != node_to_index.end(); } bool sort() { @@ -192,8 +188,6 @@ template , typename OPS = hash_ops> cla std::vector marked_cells(edges.size(), false); std::vector active_cells(edges.size(), false); std::vector active_stack; - - marked_cells.reserve(edges.size()); sorted.reserve(edges.size()); for (const auto &it : node_to_index) diff --git a/passes/cmds/glift.cc b/passes/cmds/glift.cc index faa4289e3a9..8553b02a541 100644 --- a/passes/cmds/glift.cc +++ b/passes/cmds/glift.cc @@ -582,7 +582,7 @@ struct GliftPass : public Pass { for (auto cell : module->selected_cells()) { RTLIL::Module *tpl = design->module(cell->type); if (tpl != nullptr) { - if (!topo_modules.has_edges(tpl)) + if (!topo_modules.has_node(tpl)) worklist.push_back(tpl); topo_modules.edge(tpl, module); non_top_modules.insert(cell->type); diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 7331d72a6fd..3eadd35c6af 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -424,6 +424,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons for (auto &bit : sig) outbit_to_cell[bit].insert(cell); } + cells.node(cell); } // Build the graph for the topological sort. diff --git a/passes/techmap/flatten.cc b/passes/techmap/flatten.cc index f49589b826c..4ddc4aff1fa 100644 --- a/passes/techmap/flatten.cc +++ b/passes/techmap/flatten.cc @@ -312,7 +312,7 @@ struct FlattenPass : public Pass { for (auto cell : module->selected_cells()) { RTLIL::Module *tpl = design->module(cell->type); if (tpl != nullptr) { - if (!topo_modules.has_edges(tpl)) + if (!topo_modules.has_node(tpl)) worklist.insert(tpl); topo_modules.edge(tpl, module); } From fc815fdb478056247d46deee597e09df138a168d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 00:14:52 +0000 Subject: [PATCH 116/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 688b5939ded..c6b5706cc61 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34+0 +YOSYS_VER := 0.34+7 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 6a5799cc2ed65a7481f9d1e9142b9039f78db188 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Thu, 5 Oct 2023 17:27:26 -0700 Subject: [PATCH 117/173] Add missing initialization of node_cmp_ member. --- kernel/utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/utils.h b/kernel/utils.h index 5a1279ef01c..31a8681f199 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -134,7 +134,7 @@ template , typename OPS = hash_ops> cla // We use this ordering of the edges in the adjacency matrix for // exact compatibility with an older implementation. struct IndirectCmp { - IndirectCmp(const std::vector &nodes) : nodes_(nodes) {} + IndirectCmp(const std::vector &nodes) : node_cmp_(), nodes_(nodes) {} bool operator()(int a, int b) const { log_assert(static_cast(a) < nodes_.size()); From 8367f06188edf750b32bd603552ba9d75995baf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 5 Oct 2023 19:39:28 +0200 Subject: [PATCH 118/173] ast/simplify: Remove unused in_param code --- frontends/ast/simplify.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index c5f0467041d..2a500b56bd3 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1749,13 +1749,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin bool const_fold_here = const_fold; int width_hint_here = width_hint; bool sign_hint_here = sign_hint; - bool in_param_here = in_param; if (i == 0 && (type == AST_REPLICATE || type == AST_WIRE)) const_fold_here = true; - if (i == 0 && (type == AST_GENIF || type == AST_GENCASE)) - in_param_here = true; - if (i == 1 && (type == AST_FOR || type == AST_GENFOR)) - in_param_here = true; if (type == AST_PARAMETER || type == AST_LOCALPARAM) const_fold_here = true; if (type == AST_BLOCK) { From 2ab7d1d0c85cf128f8711075584b76738e0d9b11 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 6 Oct 2023 16:05:44 +0200 Subject: [PATCH 119/173] Fix readline/editline memory leak --- kernel/yosys.cc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 559ce872cad..4409dc91ddd 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -1353,8 +1353,12 @@ void shell(RTLIL::Design *design) if ((command = fgets(command_buffer, 4096, stdin)) == NULL) break; #endif - if (command[strspn(command, " \t\r\n")] == 0) + if (command[strspn(command, " \t\r\n")] == 0) { +#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) + free(command); +#endif continue; + } #if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) add_history(command); #endif @@ -1376,10 +1380,17 @@ void shell(RTLIL::Design *design) log_reset_stack(); } design->check(); +#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) + if (command) + free(command); +#endif } if (command == NULL) printf("exit\n"); - +#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) + else + free(command); +#endif recursion_counter--; log_cmd_error_throw = false; } From bc0df04e065d53f3f1e2053861a94de29eb9e013 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Fri, 6 Oct 2023 12:53:05 -0700 Subject: [PATCH 120/173] Get rid of double lookup in TopoSort::node(). This speeds up typical TopoSort time overall by ~10%. --- kernel/utils.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/kernel/utils.h b/kernel/utils.h index 31a8681f199..8fa223824da 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -159,15 +159,12 @@ template , typename OPS = hash_ops> cla int node(T n) { - auto it = node_to_index.find(n); - if (it == node_to_index.end()) { - int index = static_cast(nodes.size()); - node_to_index[n] = index; - nodes.push_back(n); - edges.push_back(std::set(indirect_cmp)); - return index; + auto rv = node_to_index.emplace(n, static_cast(nodes.size())); + if (rv.second) { + nodes.push_back(n); + edges.push_back(std::set(indirect_cmp)); } - return it->second; + return rv.first->second; } void edge(int l_index, int r_index) { edges[r_index].insert(l_index); } From 51e9b0882bf099ee28ba88d6cc14be1f877f6cff Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 7 Oct 2023 00:14:44 +0000 Subject: [PATCH 121/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c6b5706cc61..907be74af0a 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34+7 +YOSYS_VER := 0.34+9 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 0ca39e233b8d7aa4736830cad383bc59214da12b Mon Sep 17 00:00:00 2001 From: Marcus Comstedt Date: Sat, 7 Oct 2023 10:43:00 +0200 Subject: [PATCH 122/173] scc: Use hashlib instead of STL for deterministic behaviour --- passes/cmds/scc.cc | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc index 81881832cd7..197bd931966 100644 --- a/passes/cmds/scc.cc +++ b/passes/cmds/scc.cc @@ -27,7 +27,6 @@ #include "kernel/log.h" #include #include -#include USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -39,18 +38,18 @@ struct SccWorker SigMap sigmap; CellTypes ct, specifyCells; - std::set workQueue; - std::map> cellToNextCell; - std::map cellToPrevSig, cellToNextSig; + pool workQueue; + dict> cellToNextCell; + dict cellToPrevSig, cellToNextSig; - std::map> cellLabels; - std::map cellDepth; - std::set cellsOnStack; + dict> cellLabels; + dict cellDepth; + pool cellsOnStack; std::vector cellStack; int labelCounter; - std::map cell2scc; - std::vector> sccList; + dict cell2scc; + std::vector> sccList; void run(RTLIL::Cell *cell, int depth, int maxDepth) { @@ -85,7 +84,7 @@ struct SccWorker else { log("Found an SCC:"); - std::set scc; + pool scc; while (cellsOnStack.count(cell) > 0) { RTLIL::Cell *c = cellStack.back(); cellStack.pop_back(); @@ -199,11 +198,11 @@ struct SccWorker for (auto cell : workQueue) { - cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]); + sigToNextCells.find(cellToNextSig[cell], cellToNextCell[cell]); if (!nofeedbackMode && cellToNextCell[cell].count(cell)) { log("Found an SCC:"); - std::set scc; + pool scc; log(" %s", RTLIL::id2cstr(cell->name)); cell2scc[cell] = sccList.size(); scc.insert(cell); @@ -231,7 +230,7 @@ struct SccWorker { for (int i = 0; i < int(sccList.size()); i++) { - std::set &cells = sccList[i]; + pool &cells = sccList[i]; RTLIL::SigSpec prevsig, nextsig, sig; for (auto cell : cells) { @@ -295,7 +294,7 @@ struct SccPass : public Pass { } void execute(std::vector args, RTLIL::Design *design) override { - std::map setAttr; + dict setAttr; bool allCellTypes = false; bool selectMode = false; bool nofeedbackMode = false; From c36cf9c5ac26ff6bdad8c505e0bcac677af25938 Mon Sep 17 00:00:00 2001 From: Wanda Date: Sun, 8 Oct 2023 01:11:30 +0200 Subject: [PATCH 123/173] write_verilog: avoid emitting empty cases. The Verilog grammar does not allow an empty case. Most synthesis tools are quite permissive about this, but Quartus is not. This causes problems for amaranth with Quartus (see amaranth-lang/amaranth#931). --- backends/verilog/verilog_backend.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 7099c18c349..735672a43b4 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -2008,6 +2008,11 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw dump_case_body(f, indent + " ", *it); } + if (sw->cases.empty()) { + // Verilog does not allow empty cases. + f << stringf("%s default: ;\n", indent.c_str()); + } + f << stringf("%s" "endcase\n", indent.c_str()); } From 11b9deba9f05a107c70f66139fc988be46567719 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 00:15:38 +0000 Subject: [PATCH 124/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 907be74af0a..0a9a7a2c32b 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34+9 +YOSYS_VER := 0.34+14 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 4ed708836addfd406f290aa3f191bae3b471136f Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 10 Oct 2023 11:41:33 +0200 Subject: [PATCH 125/173] verific: Use CellBaseName to identify top modules --- frontends/verific/verific.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 804b6676b6b..716b4dc1317 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2573,7 +2573,7 @@ std::string verific_import(Design *design, const std::mapAddAtt(new Att(" \\top", NULL)); nl_todo.emplace(nl->CellBaseName(), nl); - cell_name = nl->Owner()->Name(); + cell_name = nl->CellBaseName(); } if (top.empty()) cell_name = top; @@ -2595,7 +2595,7 @@ std::string verific_import(Design *design, const std::mapfirst) == 0) { VerificImporter importer(false, false, false, false, false, false, false); nl_done[it->first] = it->second; - importer.import_netlist(design, nl, nl_todo, nl->Owner()->Name() == cell_name); + importer.import_netlist(design, nl, nl_todo, nl->CellBaseName() == cell_name); } nl_todo.erase(it); } @@ -3801,7 +3801,7 @@ struct VerificPass : public Pass { VerificImporter importer(mode_gates, mode_keep, mode_nosva, mode_names, mode_verific, mode_autocover, mode_fullinit); nl_done[it->first] = it->second; - importer.import_netlist(design, nl, nl_todo, top_mod_names.count(nl->Owner()->Name())); + importer.import_netlist(design, nl, nl_todo, top_mod_names.count(nl->CellBaseName())); } nl_todo.erase(it); } From 59fbee4009f02f807d3b60888ff5eca6670e3a7f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 12 Oct 2023 00:13:29 +0000 Subject: [PATCH 126/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0a9a7a2c32b..ebe9881430c 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34+14 +YOSYS_VER := 0.34+23 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From d473a207a1692f6587516cc2b93d6f11aeff1d85 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 12 Oct 2023 09:17:06 +0200 Subject: [PATCH 127/173] Preserve VHDL architecture name in attribute --- frontends/verific/verific.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 716b4dc1317..115a42e332b 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -52,6 +52,7 @@ USING_YOSYS_NAMESPACE #ifdef VERIFIC_VHDL_SUPPORT #include "vhdl_file.h" #include "VhdlUnits.h" +#include "NameSpace.h" #endif #ifdef VERIFIC_EDIF_SUPPORT @@ -1276,6 +1277,13 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma } import_attributes(module->attributes, nl, nl); module->set_string_attribute(ID::hdlname, nl->CellBaseName()); +#ifdef VERIFIC_VHDL_SUPPORT + if (nl->IsFromVhdl()) { + NameSpace name_space(0); + char *architecture_name = name_space.ReName(nl->Name()) ; + module->set_string_attribute(ID(architecture), (architecture_name) ? architecture_name : nl->Name()); + } +#endif const char *param_name ; const char *param_value ; MapIter mi; From 62d63386886dcfec7d0087e10f52ff7c4a7796cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 12 Oct 2023 12:45:11 +0200 Subject: [PATCH 128/173] quicklogic: Fix pp3 `dffs` test Fix name confusion which was making the test look into the vendor's cell blackbox rather than into the synthesis results. --- tests/arch/quicklogic/dffs.ys | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/tests/arch/quicklogic/dffs.ys b/tests/arch/quicklogic/dffs.ys index 2e0a34540ec..e1fbef635d8 100644 --- a/tests/arch/quicklogic/dffs.ys +++ b/tests/arch/quicklogic/dffs.ys @@ -7,14 +7,27 @@ hierarchy -top my_dff proc equiv_opt -async2sync -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v synth_quicklogic # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) -cd dff # Constrain all select calls below inside the top module -select -assert-none t:* +cd my_dff # Constrain all select calls below inside the top module +select -assert-count 1 t:ckpad +select -assert-count 1 t:dffepc +select -assert-count 1 t:inpad +select -assert-count 1 t:logic_0 +select -assert-count 1 t:logic_1 +select -assert-count 1 t:outpad + +select -assert-none t:ckpad t:dffepc t:inpad t:logic_0 t:logic_1 t:outpad %% t:* %D design -load read hierarchy -top my_dffe proc equiv_opt -async2sync -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v synth_quicklogic # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) -cd dffe # Constrain all select calls below inside the top module +cd my_dffe # Constrain all select calls below inside the top module + +select -assert-count 1 t:ckpad +select -assert-count 1 t:dffepc +select -assert-count 2 t:inpad +select -assert-count 1 t:logic_0 +select -assert-count 1 t:outpad -select -assert-none t:* \ No newline at end of file +select -assert-none t:ckpad t:dffepc t:inpad t:logic_0 t:outpad %% t:* %D From 69c252f2476e01f2ea95ecb2b2f218568638f370 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 13 Oct 2023 14:32:11 +0200 Subject: [PATCH 129/173] Update abc --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ebe9881430c..6274e71a3a0 100644 --- a/Makefile +++ b/Makefile @@ -165,7 +165,7 @@ bumpversion: # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = daad9ed +ABCREV = 896e5e7 ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) From 7d30f716e82ff4782b653cb2c448062f7878c308 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 14 Oct 2023 00:14:36 +0000 Subject: [PATCH 130/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6274e71a3a0..c75bb0c66b6 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34+23 +YOSYS_VER := 0.34+27 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From a0c3be3aaeb2bbb87161432748aa349712e35dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 2 Aug 2023 13:52:40 +0200 Subject: [PATCH 131/173] peepopt: Drop unused 'initbits' code Drop code that was once used by the 'dffmux' pattern but now is unused after that pattern has been obsoleted by the 'opt_dff' pass. --- passes/pmgen/peepopt.cc | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index 9a497c91441..1d27d77a0f2 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -24,8 +24,6 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN bool did_something; -dict initbits; -pool rminitbits; #include "passes/pmgen/peepopt_pm.h" #include "generate.h" @@ -60,9 +58,6 @@ struct PeepoptPass : public Pass { if (!genmode.empty()) { - initbits.clear(); - rminitbits.clear(); - if (genmode == "shiftmul") GENERATE_PATTERN(peepopt_pm, shiftmul); else if (genmode == "muldiv") @@ -79,47 +74,13 @@ struct PeepoptPass : public Pass { while (did_something) { did_something = false; - initbits.clear(); - rminitbits.clear(); peepopt_pm pm(module); - for (auto w : module->wires()) { - auto it = w->attributes.find(ID::init); - if (it != w->attributes.end()) { - SigSpec sig = pm.sigmap(w); - Const val = it->second; - int len = std::min(GetSize(sig), GetSize(val)); - for (int i = 0; i < len; i++) { - if (sig[i].wire == nullptr) - continue; - if (val[i] != State::S0 && val[i] != State::S1) - continue; - initbits[sig[i]] = val[i]; - } - } - } - pm.setup(module->selected_cells()); pm.run_shiftmul(); pm.run_muldiv(); - - for (auto w : module->wires()) { - auto it = w->attributes.find(ID::init); - if (it != w->attributes.end()) { - SigSpec sig = pm.sigmap(w); - Const &val = it->second; - int len = std::min(GetSize(sig), GetSize(val)); - for (int i = 0; i < len; i++) { - if (rminitbits.count(sig[i])) - val[i] = State::Sx; - } - } - } - - initbits.clear(); - rminitbits.clear(); } } } From bd8a81a907f0307254387a2b74aa1d1ebc582505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 2 Aug 2023 15:44:41 +0200 Subject: [PATCH 132/173] peepopt: Clean up 'shiftmul' a bit No functional change intended. --- passes/pmgen/peepopt_shiftmul.pmg | 66 +++++++++++++++++-------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg index d71fbf74449..92e902d3ea6 100644 --- a/passes/pmgen/peepopt_shiftmul.pmg +++ b/passes/pmgen/peepopt_shiftmul.pmg @@ -3,61 +3,67 @@ pattern shiftmul // Optimize mul+shift pairs that result from expressions such as foo[s*W+:W] // -state shamt - match shift select shift->type.in($shift, $shiftx, $shr) + filter !port(shift, \B).empty() endmatch -code shamt - shamt = port(shift, \B); - if (shamt.empty()) - reject; - if (shamt[GetSize(shamt)-1] == State::S0) { - do { - shamt.remove(GetSize(shamt)-1); - if (shamt.empty()) - reject; - } while (shamt[GetSize(shamt)-1] == State::S0); - } else - if (shift->type.in($shift, $shiftx) && param(shift, \B_SIGNED).as_bool()) { +state shift_amount + +code shift_amount + shift_amount = port(shift, \B); + if (shift->type.in($shr) || !param(shift, \B_SIGNED).as_bool()) + shift_amount.append(State::S0); + + // at this point shift_amount is signed, make + // sure we can never go negative + if (shift_amount.bits().back() != State::S0) reject; + + while (shift_amount.bits().back() == State::S0) { + shift_amount.remove(GetSize(shift_amount) - 1); + if (shift_amount.empty()) reject; } - if (GetSize(shamt) > 20) + + if (GetSize(shift_amount) > 20) reject; endcode +state mul_din +state mul_const + match mul select mul->type.in($mul) - select port(mul, \A).is_fully_const() || port(mul, \B).is_fully_const() - index port(mul, \Y) === shamt + index port(mul, \Y) === shift_amount filter !param(mul, \A_SIGNED).as_bool() + + choice constport {\A, \B} + filter port(mul, constport).is_fully_const() + + define varport (constport == \A ? \B : \A) + set mul_const port(mul, constport).as_const() + set mul_din port(mul, varport) endmatch code { - IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B; - Const const_factor_cnst = port(mul, const_factor_port).as_const(); - int const_factor = const_factor_cnst.as_int(); - - if (GetSize(const_factor_cnst) == 0) + if (mul_const.empty() || GetSize(mul_const) > 20) reject; - if (GetSize(const_factor_cnst) > 20) + // make sure there's no overlap in the signal + // selections by the shiftmul pattern + if (GetSize(port(shift, \Y)) > mul_const.as_int()) reject; - if (GetSize(port(shift, \Y)) > const_factor) - reject; - - int factor_bits = ceil_log2(const_factor); - SigSpec mul_din = port(mul, const_factor_port == \A ? \B : \A); - - if (GetSize(shamt) < factor_bits+GetSize(mul_din)) + int factor_bits = ceil_log2(mul_const.as_int()); + // make sure the multiplication never wraps around + if (GetSize(shift_amount) < factor_bits + GetSize(mul_din)) reject; did_something = true; log("shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul)); + int const_factor = mul_const.as_int(); int new_const_factor = 1 << factor_bits; SigSpec padding(State::Sx, new_const_factor-const_factor); SigSpec old_a = port(shift, \A), new_a; From dd1a8ae49a54b00407afef92f5dac1b36e7efefa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 2 Aug 2023 15:46:50 +0200 Subject: [PATCH 133/173] peepopt: Try to use original wires --- passes/pmgen/peepopt_shiftmul.pmg | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg index 92e902d3ea6..177d97371b4 100644 --- a/passes/pmgen/peepopt_shiftmul.pmg +++ b/passes/pmgen/peepopt_shiftmul.pmg @@ -42,7 +42,11 @@ match mul define varport (constport == \A ? \B : \A) set mul_const port(mul, constport).as_const() - set mul_din port(mul, varport) + // get mul_din unmapped (so no `port()` shorthand) + // because we will be using it to set the \A port + // on the shift cell, and we want to stay close + // to the original design + set mul_din mul->getPort(varport) endmatch code From 038a5e1ed4d31a1ad1fde63971939abd8885fe2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 2 Aug 2023 16:10:27 +0200 Subject: [PATCH 134/173] peepopt: Support shift amounts zero-padded from below The `opt_expr` pass running before `peepopt` can interfere with the detection of a shiftmul pattern due to some of the bottom bits of the shift amount being replaced with constant zero. Extend the detection to cover those situations as well. --- passes/pmgen/peepopt_shiftmul.pmg | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg index 177d97371b4..4808430b4d3 100644 --- a/passes/pmgen/peepopt_shiftmul.pmg +++ b/passes/pmgen/peepopt_shiftmul.pmg @@ -8,9 +8,13 @@ match shift filter !port(shift, \B).empty() endmatch +// the right shift amount state shift_amount +// log2 scale factor in interpreting of shift_amount +// due to zero padding on the shift cell's B port +state log2scale -code shift_amount +code shift_amount log2scale shift_amount = port(shift, \B); if (shift->type.in($shr) || !param(shift, \B_SIGNED).as_bool()) shift_amount.append(State::S0); @@ -25,6 +29,13 @@ code shift_amount if (shift_amount.empty()) reject; } + log2scale = 0; + while (shift_amount[0] == State::S0) { + shift_amount.remove(0); + if (shift_amount.empty()) reject; + log2scale++; + } + if (GetSize(shift_amount) > 20) reject; endcode @@ -41,7 +52,7 @@ match mul filter port(mul, constport).is_fully_const() define varport (constport == \A ? \B : \A) - set mul_const port(mul, constport).as_const() + set mul_const SigSpec({port(mul, constport), SigSpec(State::S0, log2scale)}).as_const() // get mul_din unmapped (so no `port()` shorthand) // because we will be using it to set the \A port // on the shift cell, and we want to stay close @@ -61,7 +72,7 @@ code int factor_bits = ceil_log2(mul_const.as_int()); // make sure the multiplication never wraps around - if (GetSize(shift_amount) < factor_bits + GetSize(mul_din)) + if (GetSize(shift_amount) + log2scale < factor_bits + GetSize(mul_din)) reject; did_something = true; From aa9b86aeec1b1b2ea2d3344098963300b4f624f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 2 Aug 2023 18:04:54 +0200 Subject: [PATCH 135/173] peepopt: Add left-shift 'shiftmul' variant Add a separate shiftmul pattern to match on left shifts which implement demuxing. This mirrors the right shift pattern matcher but is probably best kept separate instead of merging the two into a single matcher. In any case the diff of the two matchers should be easily readable. --- passes/pmgen/Makefile.inc | 3 +- passes/pmgen/peepopt.cc | 5 +- passes/pmgen/peepopt_shiftmul_left.pmg | 160 ++++++++++++++++++ ...hiftmul.pmg => peepopt_shiftmul_right.pmg} | 4 +- 4 files changed, 167 insertions(+), 5 deletions(-) create mode 100644 passes/pmgen/peepopt_shiftmul_left.pmg rename passes/pmgen/{peepopt_shiftmul.pmg => peepopt_shiftmul_right.pmg} (95%) diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index a7ef642825c..c2257b72083 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -42,7 +42,8 @@ GENFILES += passes/pmgen/peepopt_pm.h passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h $(eval $(call add_extra_objs,passes/pmgen/peepopt_pm.h)) -PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg +PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul_right.pmg +PEEPOPT_PATTERN += passes/pmgen/peepopt_shiftmul_left.pmg PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index 1d27d77a0f2..2b225623dba 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -59,7 +59,7 @@ struct PeepoptPass : public Pass { if (!genmode.empty()) { if (genmode == "shiftmul") - GENERATE_PATTERN(peepopt_pm, shiftmul); + GENERATE_PATTERN(peepopt_pm, shiftmul_right); else if (genmode == "muldiv") GENERATE_PATTERN(peepopt_pm, muldiv); else @@ -79,7 +79,8 @@ struct PeepoptPass : public Pass { pm.setup(module->selected_cells()); - pm.run_shiftmul(); + pm.run_shiftmul_right(); + pm.run_shiftmul_left(); pm.run_muldiv(); } } diff --git a/passes/pmgen/peepopt_shiftmul_left.pmg b/passes/pmgen/peepopt_shiftmul_left.pmg new file mode 100644 index 00000000000..607f8368c53 --- /dev/null +++ b/passes/pmgen/peepopt_shiftmul_left.pmg @@ -0,0 +1,160 @@ +pattern shiftmul_left +// +// Optimize mul+shift pairs that result from expressions such as foo[s*W+:W] +// + +match shift + select shift->type.in($shift, $shiftx, $shl) + select shift->type.in($shl) || param(shift, \B_SIGNED).as_bool() + filter !port(shift, \B).empty() +endmatch + +match neg + if shift->type.in($shift, $shiftx) + select neg->type == $neg + index port(neg, \Y) === port(shift, \B) + filter !port(shift, \A).empty() +endmatch + +// the left shift amount +state shift_amount +// log2 scale factor in interpreting of shift_amount +// due to zero padding on the shift cell's B port +state log2scale + +code shift_amount log2scale + if (neg) { + // case of `$shift`, `$shiftx` + shift_amount = port(neg, \A); + if (!param(neg, \A_SIGNED).as_bool()) + shift_amount.append(State::S0); + } else { + // case of `$shl` + shift_amount = port(shift, \B); + if (!param(shift, \B_SIGNED).as_bool()) + shift_amount.append(State::S0); + } + + // at this point shift_amount is signed, make + // sure we can never go negative + if (shift_amount.bits().back() != State::S0) + reject; + + while (shift_amount.bits().back() == State::S0) { + shift_amount.remove(GetSize(shift_amount) - 1); + if (shift_amount.empty()) reject; + } + + log2scale = 0; + while (shift_amount[0] == State::S0) { + shift_amount.remove(0); + if (shift_amount.empty()) reject; + log2scale++; + } + + if (GetSize(shift_amount) > 20) + reject; +endcode + +state mul_din +state mul_const + +match mul + select mul->type.in($mul) + index port(mul, \Y) === shift_amount + filter !param(mul, \A_SIGNED).as_bool() + + choice constport {\A, \B} + filter port(mul, constport).is_fully_const() + + define varport (constport == \A ? \B : \A) + set mul_const SigSpec({port(mul, constport), SigSpec(State::S0, log2scale)}).as_const() + // get mul_din unmapped (so no `port()` shorthand) + // because we will be using it to set the \A port + // on the shift cell, and we want to stay close + // to the original design + set mul_din mul->getPort(varport) +endmatch + +code +{ + if (mul_const.empty() || GetSize(mul_const) > 20) + reject; + + // make sure there's no overlap in the signal + // selections by the shiftmul pattern + if (GetSize(port(shift, \A)) > mul_const.as_int()) + reject; + + int factor_bits = ceil_log2(mul_const.as_int()); + // make sure the multiplication never wraps around + if (GetSize(shift_amount) < factor_bits + GetSize(mul_din)) + reject; + + if (neg) { + // make sure the negation never wraps around + if (GetSize(port(shift, \B)) < factor_bits + GetSize(mul_din) + + log2scale + 1) + reject; + } + + did_something = true; + log("left shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul)); + + int const_factor = mul_const.as_int(); + int new_const_factor = 1 << factor_bits; + SigSpec padding(State::Sm, new_const_factor-const_factor); + SigSpec old_y = port(shift, \Y), new_y; + int trunc = 0; + + if (GetSize(old_y) % const_factor != 0) { + trunc = const_factor - GetSize(old_y) % const_factor; + old_y.append(SigSpec(State::Sm, trunc)); + } + + for (int i = 0; i*const_factor < GetSize(old_y); i++) { + SigSpec slice = old_y.extract(i*const_factor, const_factor); + new_y.append(slice); + new_y.append(padding); + } + + if (trunc > 0) + new_y.remove(GetSize(new_y)-trunc, trunc); + + { + // Now replace occurences of Sm in new_y with bits + // of a dummy wire + int padbits = 0; + for (auto bit : new_y) + if (bit == SigBit(State::Sm)) + padbits++; + + SigSpec padwire = module->addWire(NEW_ID, padbits); + + for (int i = new_y.size() - 1; i >= 0; i--) + if (new_y[i] == SigBit(State::Sm)) { + new_y[i] = padwire.bits().back(); + padwire.remove(padwire.size() - 1); + } + } + + SigSpec new_b = {mul_din, SigSpec(State::S0, factor_bits)}; + + shift->setPort(\Y, new_y); + shift->setParam(\Y_WIDTH, GetSize(new_y)); + if (shift->type == $shl) { + if (param(shift, \B_SIGNED).as_bool()) + new_b.append(State::S0); + shift->setPort(\B, new_b); + shift->setParam(\B_WIDTH, GetSize(new_b)); + } else { + SigSpec b_neg = module->addWire(NEW_ID, GetSize(new_b) + 1); + module->addNeg(NEW_ID, new_b, b_neg); + shift->setPort(\B, b_neg); + shift->setParam(\B_WIDTH, GetSize(b_neg)); + } + + blacklist(shift); + accept; +} +endcode diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul_right.pmg similarity index 95% rename from passes/pmgen/peepopt_shiftmul.pmg rename to passes/pmgen/peepopt_shiftmul_right.pmg index 4808430b4d3..71e0980234a 100644 --- a/passes/pmgen/peepopt_shiftmul.pmg +++ b/passes/pmgen/peepopt_shiftmul_right.pmg @@ -1,4 +1,4 @@ -pattern shiftmul +pattern shiftmul_right // // Optimize mul+shift pairs that result from expressions such as foo[s*W+:W] // @@ -76,7 +76,7 @@ code reject; did_something = true; - log("shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul)); + log("right shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul)); int const_factor = mul_const.as_int(); int new_const_factor = 1 << factor_bits; From 5c0c8251c38f103aa63e5cf1e689c64803ba7e16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 16 Oct 2023 13:54:17 +0200 Subject: [PATCH 136/173] peepopt: Remove broken `-generate` option --- passes/pmgen/peepopt.cc | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index 2b225623dba..f0349525472 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -26,7 +26,6 @@ PRIVATE_NAMESPACE_BEGIN bool did_something; #include "passes/pmgen/peepopt_pm.h" -#include "generate.h" struct PeepoptPass : public Pass { PeepoptPass() : Pass("peepopt", "collection of peephole optimizers") { } @@ -41,32 +40,15 @@ struct PeepoptPass : public Pass { } void execute(std::vector args, RTLIL::Design *design) override { - std::string genmode; - log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-generate" && argidx+1 < args.size()) { - genmode = args[++argidx]; - continue; - } break; } extra_args(args, argidx, design); - if (!genmode.empty()) - { - if (genmode == "shiftmul") - GENERATE_PATTERN(peepopt_pm, shiftmul_right); - else if (genmode == "muldiv") - GENERATE_PATTERN(peepopt_pm, muldiv); - else - log_abort(); - return; - } - for (auto module : design->selected_modules()) { did_something = true; From 660be4a31e58f7d348fea9b3fe41553ac061f26a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 16 Oct 2023 14:08:42 +0200 Subject: [PATCH 137/173] peepopt: Describe rules in help message --- passes/pmgen/peepopt.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index f0349525472..aef464d79c9 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -37,6 +37,17 @@ struct PeepoptPass : public Pass { log("\n"); log("This pass applies a collection of peephole optimizers to the current design.\n"); log("\n"); + log("This pass employs the following rules:\n"); + log("\n"); + log(" * muldiv - Replace (A*B)/B with A\n"); + log("\n"); + log(" * shiftmul - Replace A>>(B*C) with A'>>(B< args, RTLIL::Design *design) override { From d6d1cc705e524264361bfc16f7a2ef5a96b0b717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 16 Oct 2023 14:16:36 +0200 Subject: [PATCH 138/173] pmgen: Fix sample syntax --- passes/pmgen/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md index 39560839f0f..3205be1b55e 100644 --- a/passes/pmgen/README.md +++ b/passes/pmgen/README.md @@ -212,7 +212,7 @@ second argument, and the matcher will iterate over those options: index port(eq, BA) === bar set eq_ab AB set eq_ba BA - generate + endmatch Notice how `define` can be used to define additional local variables similar to the loop variables defined by `slice` and `choice`. From a5c04dd72e3d02d36dadf1c60ae76bb149969970 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 17 Oct 2023 00:15:28 +0000 Subject: [PATCH 139/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c75bb0c66b6..b89c87ae943 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34+27 +YOSYS_VER := 0.34+43 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 1b6d1e941950576f16140e43a53c1694cddb1092 Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Thu, 19 Oct 2023 19:12:36 +0200 Subject: [PATCH 140/173] memory_libmap: look for ram_style attributes on surrounding signals --- kernel/constids.inc | 1 + kernel/mem.cc | 6 +++ passes/memory/memory_libmap.cc | 44 ++++++++++++++++--- tests/memlib/generate.py | 22 ++++++++++ tests/verific/rom_case.ys | 78 ++++++++++++++++++++++++++++++++++ 5 files changed, 146 insertions(+), 5 deletions(-) create mode 100644 tests/verific/rom_case.ys diff --git a/kernel/constids.inc b/kernel/constids.inc index 93101282a0b..480e2afc6fa 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -140,6 +140,7 @@ X(nomem2reg) X(nomeminit) X(nosync) X(nowrshmsk) +X(no_ram) X(no_rw_check) X(O) X(OFFSET) diff --git a/kernel/mem.cc b/kernel/mem.cc index 269a476a125..40345b81df1 100644 --- a/kernel/mem.cc +++ b/kernel/mem.cc @@ -148,6 +148,8 @@ void Mem::emit() { for (int j = 0; j < (1 << wr_ports[i].wide_log2); j++) wr_port_xlat.push_back(i); for (auto &port : rd_ports) { + for (auto attr: port.attributes) + cell->attributes.insert(attr); if (port.cell) { module->remove(port.cell); port.cell = nullptr; @@ -210,6 +212,8 @@ void Mem::emit() { cell->setPort(ID::RD_ADDR, rd_addr); cell->setPort(ID::RD_DATA, rd_data); for (auto &port : wr_ports) { + for (auto attr: port.attributes) + cell->attributes.insert(attr); if (port.cell) { module->remove(port.cell); port.cell = nullptr; @@ -246,6 +250,8 @@ void Mem::emit() { cell->setPort(ID::WR_ADDR, wr_addr); cell->setPort(ID::WR_DATA, wr_data); for (auto &init : inits) { + for (auto attr: init.attributes) + cell->attributes.insert(attr); if (init.cell) { module->remove(init.cell); init.cell = nullptr; diff --git a/passes/memory/memory_libmap.cc b/passes/memory/memory_libmap.cc index f8b0eec1d8d..e39a518b761 100644 --- a/passes/memory/memory_libmap.cc +++ b/passes/memory/memory_libmap.cc @@ -481,18 +481,49 @@ void MemMapping::dump_config(MemConfig &cfg) { } } +std::pair search_for_attribute(Mem mem, IdString attr) { + if (mem.has_attribute(attr)) + return std::make_pair(true, mem.attributes.at(attr)); + for (auto &port: mem.rd_ports){ + if (port.has_attribute(attr)) + return std::make_pair(true, port.attributes.at(attr)); + log_debug("looking for attribute %s on signal %s\n", log_id(attr), log_signal(port.data)); + for (SigBit bit: port.data) + if (bit.is_wire() && bit.wire->has_attribute(attr)) + return std::make_pair(true, bit.wire->attributes.at(attr)); + log_debug("looking for attribute %s on signal %s\n", log_id(attr), log_signal(port.data)); + for (SigBit bit: port.addr) + if (bit.is_wire() && bit.wire->has_attribute(attr)) + return std::make_pair(true, bit.wire->attributes.at(attr)); + } + for (auto &port: mem.wr_ports){ + if (port.has_attribute(attr)) + return std::make_pair(true, port.attributes.at(attr)); + log_debug("looking for attribute %s on signal %s\n", log_id(attr), log_signal(port.data)); + for (SigBit bit: port.data) + if (bit.is_wire() && bit.wire->has_attribute(attr)) + return std::make_pair(true, bit.wire->attributes.at(attr)); + for (SigBit bit: port.addr) + if (bit.is_wire() && bit.wire->has_attribute(attr)) + return std::make_pair(true, bit.wire->attributes.at(attr)); + } + return std::make_pair(false, Const()); +} + // Go through memory attributes to determine user-requested mapping style. void MemMapping::determine_style() { kind = RamKind::Auto; style = ""; - if (mem.get_bool_attribute(ID::lram)) { + auto find_attr = search_for_attribute(mem, ID::lram); + if (find_attr.first && find_attr.second.as_bool()) { kind = RamKind::Huge; log("found attribute 'lram' on memory %s.%s, forced mapping to huge RAM\n", log_id(mem.module->name), log_id(mem.memid)); return; } for (auto attr: {ID::ram_block, ID::rom_block, ID::ram_style, ID::rom_style, ID::ramstyle, ID::romstyle, ID::syn_ramstyle, ID::syn_romstyle}) { - if (mem.has_attribute(attr)) { - Const val = mem.attributes.at(attr); + find_attr = search_for_attribute(mem, attr); + if (find_attr.first) { + Const val = find_attr.second; if (val == 1) { kind = RamKind::NotLogic; log("found attribute '%s = 1' on memory %s.%s, disabled mapping to FF\n", log_id(attr), log_id(mem.module->name), log_id(mem.memid)); @@ -526,8 +557,11 @@ void MemMapping::determine_style() { return; } } - if (mem.get_bool_attribute(ID::logic_block)) - kind = RamKind::Logic; + for (auto attr: {ID::logic_block, ID::no_ram}){ + find_attr = search_for_attribute(mem, attr); + if (find_attr.first && find_attr.second.as_bool()) + kind = RamKind::Logic; + } } // Determine whether the memory can be mapped entirely to soft logic. diff --git a/tests/memlib/generate.py b/tests/memlib/generate.py index f40210501db..46eff6b43e3 100644 --- a/tests/memlib/generate.py +++ b/tests/memlib/generate.py @@ -1513,6 +1513,28 @@ def __init__(self, name, src, libs, defs, cells): ["block_sp_full"], defs, {"RAM_BLOCK_SP": 1, "$*": add_logic} )) + +ROM_CASE = """ +module rom(input clk, input [2:0] addr, {attr}output reg [7:0] data); + +always @(posedge clk) begin + case (addr) + 3'b000: data <= 8'h12; + 3'b001: data <= 8'hAB; + 3'b010: data <= 8'h42; + 3'b011: data <= 8'h23; + 3'b100: data <= 8'h66; + 3'b101: data <= 8'hC0; + 3'b110: data <= 8'h3F; + 3'b111: data <= 8'h95; + endcase +end + +endmodule +""" + +TESTS.append(Test("rom_case", ROM_CASE.format(attr=""), ["block_sdp"], [], {"RAM_BLOCK_SDP" : 0})) +TESTS.append(Test("rom_case_block", ROM_CASE.format(attr="(* rom_style = \"block\" *) "), ["block_sdp"], [], {"RAM_BLOCK_SDP" : 1})) with open("run-test.mk", "w") as mf: mf.write("ifneq ($(strip $(SEED)),)\n") diff --git a/tests/verific/rom_case.ys b/tests/verific/rom_case.ys new file mode 100644 index 00000000000..171c16db766 --- /dev/null +++ b/tests/verific/rom_case.ys @@ -0,0 +1,78 @@ +verific -sv < data <= X"12"; + when "001" => data <= X"AB"; + when "010" => data <= X"42"; + when "011" => data <= X"23"; + when "100" => data <= X"66"; + when "101" => data <= X"C0"; + when "110" => data <= X"3F"; + when others => data <= X"95"; + end case; + end if; + end process p_rom; + +end architecture rtl; +EOF +hierarchy -top rom +proc +opt +opt -full +memory -nomap +dump +memory_libmap -lib ../memlib/memlib_block_sdp.txt +memory_map +stat +select -assert-count 1 t:RAM_BLOCK_SDP \ No newline at end of file From 833b67af80a748b7c1f8a775c5721b2815151f34 Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Fri, 20 Oct 2023 18:31:41 +0200 Subject: [PATCH 141/173] verific: import attributes on ports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Miodrag Milanović --- frontends/verific/verific.cc | 7 ++++++- tests/verific/memory_semantics.ys | 4 ++-- tests/verific/rom_case.ys | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 115a42e332b..5ac8f8b393c 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1345,7 +1345,12 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex()); wire->upto = portbus->IsUp(); import_attributes(wire->attributes, portbus, nl); - + SetIter si ; + Port *port ; + FOREACH_PORT_OF_PORTBUS(portbus, si, port) { + import_attributes(wire->attributes, port->GetNet(), nl); + break; + } bool portbus_input = portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_IN; if (portbus_input) wire->port_input = true; diff --git a/tests/verific/memory_semantics.ys b/tests/verific/memory_semantics.ys index 92f4fd2dc44..adcd3a4ca7c 100644 --- a/tests/verific/memory_semantics.ys +++ b/tests/verific/memory_semantics.ys @@ -26,9 +26,9 @@ reg [DEPTH_LOG2-1:0] counter = 0; reg done = 1'b0; always @(posedge clk) begin if (!done) - counter = counter + 1; + counter = counter + 1'b1; if (counter == 0) - done = 1; + done = 1'b1; end wire [WIDTH-1:0] old_data = PRIME1 * counter; diff --git a/tests/verific/rom_case.ys b/tests/verific/rom_case.ys index 171c16db766..253cc0766ef 100644 --- a/tests/verific/rom_case.ys +++ b/tests/verific/rom_case.ys @@ -30,7 +30,7 @@ select -assert-count 1 t:RAM_BLOCK_SDP design -reset -verific -vhdl << +verific -vhdl < Date: Tue, 24 Oct 2023 13:55:45 +0200 Subject: [PATCH 142/173] memory_libmap: update search order for attributes --- passes/memory/memory_libmap.cc | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/passes/memory/memory_libmap.cc b/passes/memory/memory_libmap.cc index e39a518b761..ec181a142c4 100644 --- a/passes/memory/memory_libmap.cc +++ b/passes/memory/memory_libmap.cc @@ -482,31 +482,40 @@ void MemMapping::dump_config(MemConfig &cfg) { } std::pair search_for_attribute(Mem mem, IdString attr) { + // priority of attributes: + // 1. attributes on memory itself + // 2. attributes on a read or write port + // 3. attributes on data signal of a read or write port + // 4. attributes on address signal of a read or write port + if (mem.has_attribute(attr)) return std::make_pair(true, mem.attributes.at(attr)); - for (auto &port: mem.rd_ports){ + + for (auto &port: mem.rd_ports) + if (port.has_attribute(attr)) + return std::make_pair(true, port.attributes.at(attr)); + for (auto &port: mem.wr_ports) if (port.has_attribute(attr)) return std::make_pair(true, port.attributes.at(attr)); - log_debug("looking for attribute %s on signal %s\n", log_id(attr), log_signal(port.data)); + + for (auto &port: mem.rd_ports) for (SigBit bit: port.data) if (bit.is_wire() && bit.wire->has_attribute(attr)) return std::make_pair(true, bit.wire->attributes.at(attr)); - log_debug("looking for attribute %s on signal %s\n", log_id(attr), log_signal(port.data)); - for (SigBit bit: port.addr) + for (auto &port: mem.wr_ports) + for (SigBit bit: port.data) if (bit.is_wire() && bit.wire->has_attribute(attr)) return std::make_pair(true, bit.wire->attributes.at(attr)); - } - for (auto &port: mem.wr_ports){ - if (port.has_attribute(attr)) - return std::make_pair(true, port.attributes.at(attr)); - log_debug("looking for attribute %s on signal %s\n", log_id(attr), log_signal(port.data)); - for (SigBit bit: port.data) + + for (auto &port: mem.rd_ports) + for (SigBit bit: port.addr) if (bit.is_wire() && bit.wire->has_attribute(attr)) return std::make_pair(true, bit.wire->attributes.at(attr)); + for (auto &port: mem.wr_ports) for (SigBit bit: port.addr) if (bit.is_wire() && bit.wire->has_attribute(attr)) return std::make_pair(true, bit.wire->attributes.at(attr)); - } + return std::make_pair(false, Const()); } From 6ffc3159360d8d7992af02cbc483718dd07c812e Mon Sep 17 00:00:00 2001 From: Catherine Date: Mon, 9 Oct 2023 11:45:12 +0000 Subject: [PATCH 143/173] cxxrtl: export wire attributes through the C API. Co-authored-by: Charlotte --- backends/cxxrtl/cxxrtl.h | 48 +++++++++++++--- backends/cxxrtl/cxxrtl_backend.cc | 91 ++++++++++++++++++++----------- backends/cxxrtl/cxxrtl_capi.cc | 43 +++++++++++++++ backends/cxxrtl/cxxrtl_capi.h | 65 ++++++++++++++++++++++ 4 files changed, 207 insertions(+), 40 deletions(-) diff --git a/backends/cxxrtl/cxxrtl.h b/backends/cxxrtl/cxxrtl.h index 8f5e4035a34..b2871ee19df 100644 --- a/backends/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/cxxrtl.h @@ -1019,14 +1019,14 @@ struct metadata { // In debug mode, using the wrong .as_*() function will assert. // In release mode, using the wrong .as_*() function will safely return a default value. - const unsigned uint_value = 0; - const signed sint_value = 0; + const uint64_t uint_value = 0; + const int64_t sint_value = 0; const std::string string_value = ""; const double double_value = 0.0; metadata() : value_type(MISSING) {} - metadata(unsigned value) : value_type(UINT), uint_value(value) {} - metadata(signed value) : value_type(SINT), sint_value(value) {} + metadata(uint64_t value) : value_type(UINT), uint_value(value) {} + metadata(int64_t value) : value_type(SINT), sint_value(value) {} metadata(const std::string &value) : value_type(STRING), string_value(value) {} metadata(const char *value) : value_type(STRING), string_value(value) {} metadata(double value) : value_type(DOUBLE), double_value(value) {} @@ -1034,12 +1034,12 @@ struct metadata { metadata(const metadata &) = default; metadata &operator=(const metadata &) = delete; - unsigned as_uint() const { + uint64_t as_uint() const { assert(value_type == UINT); return uint_value; } - signed as_sint() const { + int64_t as_sint() const { assert(value_type == SINT); return sint_value; } @@ -1068,6 +1068,9 @@ using debug_outline = ::_cxxrtl_outline; // // To avoid violating strict aliasing rules, this structure has to be a subclass of the one used // in the C API, or it would not be possible to cast between the pointers to these. +// +// The `attrs` member cannot be owned by this structure because a `cxxrtl_object` can be created +// from external C code. struct debug_item : ::cxxrtl_object { // Object types. enum : uint32_t { @@ -1103,6 +1106,7 @@ struct debug_item : ::cxxrtl_object { curr = item.data; next = item.data; outline = nullptr; + attrs = nullptr; } template @@ -1118,6 +1122,7 @@ struct debug_item : ::cxxrtl_object { curr = const_cast(item.data); next = nullptr; outline = nullptr; + attrs = nullptr; } template @@ -1134,6 +1139,7 @@ struct debug_item : ::cxxrtl_object { curr = item.curr.data; next = item.next.data; outline = nullptr; + attrs = nullptr; } template @@ -1149,6 +1155,7 @@ struct debug_item : ::cxxrtl_object { curr = item.data ? item.data[0].data : nullptr; next = nullptr; outline = nullptr; + attrs = nullptr; } template @@ -1164,6 +1171,7 @@ struct debug_item : ::cxxrtl_object { curr = const_cast(item.data); next = nullptr; outline = nullptr; + attrs = nullptr; } template @@ -1180,6 +1188,7 @@ struct debug_item : ::cxxrtl_object { curr = const_cast(item.curr.data); next = nullptr; outline = nullptr; + attrs = nullptr; } template @@ -1195,6 +1204,7 @@ struct debug_item : ::cxxrtl_object { curr = const_cast(item.data); next = nullptr; outline = &group; + attrs = nullptr; } template @@ -1215,10 +1225,28 @@ struct debug_item : ::cxxrtl_object { }; static_assert(std::is_standard_layout::value, "debug_item is not compatible with C layout"); +} // namespace cxxrtl + +typedef struct _cxxrtl_attr_set { + cxxrtl::metadata_map map; +} *cxxrtl_attr_set; + +namespace cxxrtl { + +// Representation of an attribute set in the C++ interface. +using debug_attrs = ::_cxxrtl_attr_set; + struct debug_items { std::map> table; - - void add(const std::string &name, debug_item &&item) { + std::map> attrs_table; + + void add(const std::string &name, debug_item &&item, metadata_map &&item_attrs = {}) { + std::unique_ptr &attrs = attrs_table[name]; + if (attrs.get() == nullptr) + attrs = std::unique_ptr(new debug_attrs); + for (auto attr : item_attrs) + attrs->map.insert(attr); + item.attrs = attrs.get(); std::vector &parts = table[name]; parts.emplace_back(item); std::sort(parts.begin(), parts.end(), @@ -1246,6 +1274,10 @@ struct debug_items { const debug_item &operator [](const std::string &name) const { return at(name); } + + const metadata_map &attrs(const std::string &name) const { + return attrs_table.at(name)->map; + } }; // Tag class to disambiguate the default constructor used by the toplevel module that calls reset(), diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index 7696ae5747c..3fd4857bd51 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -2120,6 +2120,46 @@ struct CxxrtlWorker { dec_indent(); } + void dump_metadata_map(const dict &metadata_map) + { + if (metadata_map.empty()) { + f << "metadata_map()"; + return; + } + f << "metadata_map({\n"; + inc_indent(); + for (auto metadata_item : metadata_map) { + if (!metadata_item.first.isPublic()) + continue; + if (metadata_item.second.size() > 64 && (metadata_item.second.flags & RTLIL::CONST_FLAG_STRING) == 0) { + f << indent << "/* attribute " << metadata_item.first.str().substr(1) << " is over 64 bits wide */"; + continue; + } + f << indent << "{ " << escape_cxx_string(metadata_item.first.str().substr(1)) << ", "; + // In Yosys, a real is a type of string. + if (metadata_item.second.flags & RTLIL::CONST_FLAG_REAL) { + f << std::showpoint << std::stod(metadata_item.second.decode_string()) << std::noshowpoint; + } else if (metadata_item.second.flags & RTLIL::CONST_FLAG_STRING) { + f << escape_cxx_string(metadata_item.second.decode_string()); + } else if (metadata_item.second.flags & RTLIL::CONST_FLAG_SIGNED) { + f << "INT64_C(" << metadata_item.second.as_int(/*is_signed=*/true) << ")"; + } else { + f << "UINT64_C(" << metadata_item.second.as_int(/*is_signed=*/false) << ")"; + } + f << " },\n"; + } + dec_indent(); + f << indent << "})"; + } + + void dump_debug_attrs(const RTLIL::AttrObject *object) + { + dict attributes = object->attributes; + // Inherently necessary to get access to the object, so a waste of space to emit. + attributes.erase(ID::hdlname); + dump_metadata_map(attributes); + } + void dump_debug_info_method(RTLIL::Module *module) { size_t count_public_wires = 0; @@ -2205,7 +2245,9 @@ struct CxxrtlWorker { } f << "debug_item::" << flag; } - f << "));\n"; + f << "), "; + dump_debug_attrs(wire); + f << ");\n"; count_member_wires++; break; } @@ -2220,7 +2262,9 @@ struct CxxrtlWorker { f << "debug_eval_outline"; else f << "debug_alias()"; - f << ", " << mangle(aliasee) << ", " << wire->start_offset << "));\n"; + f << ", " << mangle(aliasee) << ", " << wire->start_offset << "), "; + dump_debug_attrs(aliasee); + f << ");\n"; count_alias_wires++; break; } @@ -2230,14 +2274,18 @@ struct CxxrtlWorker { dump_const(debug_wire_type.sig_subst.as_const()); f << ";\n"; f << indent << "items.add(path + " << escape_cxx_string(get_hdl_name(wire)); - f << ", debug_item(const_" << mangle(wire) << ", " << wire->start_offset << "));\n"; + f << ", debug_item(const_" << mangle(wire) << ", " << wire->start_offset << "), "; + dump_debug_attrs(wire); + f << ");\n"; count_const_wires++; break; } case WireType::OUTLINE: { // Localized or inlined, but rematerializable wire f << indent << "items.add(path + " << escape_cxx_string(get_hdl_name(wire)); - f << ", debug_item(debug_eval_outline, " << mangle(wire) << ", " << wire->start_offset << "));\n"; + f << ", debug_item(debug_eval_outline, " << mangle(wire) << ", " << wire->start_offset << "), "; + dump_debug_attrs(wire); + f << ");\n"; count_inline_wires++; break; } @@ -2254,7 +2302,13 @@ struct CxxrtlWorker { continue; f << indent << "items.add(path + " << escape_cxx_string(mem.packed ? get_hdl_name(mem.cell) : get_hdl_name(mem.mem)); f << ", debug_item(" << mangle(&mem) << ", "; - f << mem.start_offset << "));\n"; + f << mem.start_offset << "), "; + if (mem.packed) { + dump_debug_attrs(mem.cell); + } else { + dump_debug_attrs(mem.mem); + } + f << ");\n"; } for (auto cell : module->cells()) { if (is_internal_cell(cell->type)) @@ -2282,33 +2336,6 @@ struct CxxrtlWorker { } } - void dump_metadata_map(const dict &metadata_map) - { - if (metadata_map.empty()) { - f << "metadata_map()"; - return; - } - f << "metadata_map({\n"; - inc_indent(); - for (auto metadata_item : metadata_map) { - if (!metadata_item.first.begins_with("\\")) - continue; - f << indent << "{ " << escape_cxx_string(metadata_item.first.str().substr(1)) << ", "; - if (metadata_item.second.flags & RTLIL::CONST_FLAG_REAL) { - f << std::showpoint << std::stod(metadata_item.second.decode_string()) << std::noshowpoint; - } else if (metadata_item.second.flags & RTLIL::CONST_FLAG_STRING) { - f << escape_cxx_string(metadata_item.second.decode_string()); - } else { - f << metadata_item.second.as_int(/*is_signed=*/metadata_item.second.flags & RTLIL::CONST_FLAG_SIGNED); - if (!(metadata_item.second.flags & RTLIL::CONST_FLAG_SIGNED)) - f << "u"; - } - f << " },\n"; - } - dec_indent(); - f << indent << "})"; - } - void dump_module_intf(RTLIL::Module *module) { dump_attrs(module); diff --git a/backends/cxxrtl/cxxrtl_capi.cc b/backends/cxxrtl/cxxrtl_capi.cc index 227173ba87f..d50ddcd6941 100644 --- a/backends/cxxrtl/cxxrtl_capi.cc +++ b/backends/cxxrtl/cxxrtl_capi.cc @@ -90,3 +90,46 @@ void cxxrtl_enum(cxxrtl_handle handle, void *data, void cxxrtl_outline_eval(cxxrtl_outline outline) { outline->eval(); } + +int cxxrtl_attr_type(cxxrtl_attr_set attrs_, const char *name) { + auto attrs = (cxxrtl::metadata_map*)attrs_; + if (!attrs->count(name)) + return CXXRTL_ATTR_NONE; + switch (attrs->at(name).value_type) { + case cxxrtl::metadata::UINT: + return CXXRTL_ATTR_UNSIGNED_INT; + case cxxrtl::metadata::SINT: + return CXXRTL_ATTR_SIGNED_INT; + case cxxrtl::metadata::STRING: + return CXXRTL_ATTR_STRING; + case cxxrtl::metadata::DOUBLE: + return CXXRTL_ATTR_DOUBLE; + default: + // Present unsupported attribute type the same way as no attribute at all. + return CXXRTL_ATTR_NONE; + } +} + +uint64_t cxxrtl_attr_get_unsigned_int(cxxrtl_attr_set attrs_, const char *name) { + auto &attrs = *(cxxrtl::metadata_map*)attrs_; + assert(attrs.count(name) && attrs.at(name).value_type == cxxrtl::metadata::UINT); + return attrs[name].as_uint(); +} + +int64_t cxxrtl_attr_get_signed_int(cxxrtl_attr_set attrs_, const char *name) { + auto &attrs = *(cxxrtl::metadata_map*)attrs_; + assert(attrs.count(name) && attrs.at(name).value_type == cxxrtl::metadata::SINT); + return attrs[name].as_sint(); +} + +const char *cxxrtl_attr_get_string(cxxrtl_attr_set attrs_, const char *name) { + auto &attrs = *(cxxrtl::metadata_map*)attrs_; + assert(attrs.count(name) && attrs.at(name).value_type == cxxrtl::metadata::STRING); + return attrs[name].as_string().c_str(); +} + +double cxxrtl_attr_get_double(cxxrtl_attr_set attrs_, const char *name) { + auto &attrs = *(cxxrtl::metadata_map*)attrs_; + assert(attrs.count(name) && attrs.at(name).value_type == cxxrtl::metadata::DOUBLE); + return attrs[name].as_double(); +} diff --git a/backends/cxxrtl/cxxrtl_capi.h b/backends/cxxrtl/cxxrtl_capi.h index 2df2b7287f4..e5c84bf656a 100644 --- a/backends/cxxrtl/cxxrtl_capi.h +++ b/backends/cxxrtl/cxxrtl_capi.h @@ -249,6 +249,15 @@ struct cxxrtl_object { // this field to NULL. struct _cxxrtl_outline *outline; + // Opaque reference to an attribute set. + // + // See the documentation of `cxxrtl_attr_set` for details. When creating a `cxxrtl_object`, set + // this field to NULL. + // + // The lifetime of the pointers returned by `cxxrtl_attr_*` family of functions is the same as + // the lifetime of this structure. + struct _cxxrtl_attr_set *attrs; + // More description fields may be added in the future, but the existing ones will never change. }; @@ -304,6 +313,62 @@ typedef struct _cxxrtl_outline *cxxrtl_outline; // re-evaluated, otherwise the bits read from that object are meaningless. void cxxrtl_outline_eval(cxxrtl_outline outline); +// Opaque reference to an attribute set. +// +// An attribute set is a map between attribute names (always strings) and values (which may have +// several different types). To find out the type of an attribute, use `cxxrtl_attr_type`, and +// to retrieve the value of an attribute, use `cxxrtl_attr_as_string`. +typedef struct _cxxrtl_attr_set *cxxrtl_attr_set; + +// Type of an attribute. +enum cxxrtl_attr_type { + // Attribute is not present. + CXXRTL_ATTR_NONE = 0, + + // Attribute has an unsigned integer value. + CXXRTL_ATTR_UNSIGNED_INT = 1, + + // Attribute has an unsigned integer value. + CXXRTL_ATTR_SIGNED_INT = 2, + + // Attribute has a string value. + CXXRTL_ATTR_STRING = 3, + + // Attribute has a double precision floating point value. + CXXRTL_ATTR_DOUBLE = 4, + + // More attribute types may be defined in the future, but the existing values will never change. +}; + +// Determine the presence and type of an attribute in an attribute set. +// +// This function returns one of the possible `cxxrtl_attr_type` values. +int cxxrtl_attr_type(cxxrtl_attr_set attrs, const char *name); + +// Retrieve an unsigned integer valued attribute from an attribute set. +// +// This function asserts that `cxxrtl_attr_type(attrs, name) == CXXRTL_ATTR_UNSIGNED_INT`. +// If assertions are disabled, returns 0 if the attribute is missing or has an incorrect type. +uint64_t cxxrtl_attr_get_unsigned_int(cxxrtl_attr_set attrs, const char *name); + +// Retrieve a signed integer valued attribute from an attribute set. +// +// This function asserts that `cxxrtl_attr_type(attrs, name) == CXXRTL_ATTR_SIGNED_INT`. +// If assertions are disabled, returns 0 if the attribute is missing or has an incorrect type. +int64_t cxxrtl_attr_get_signed_int(cxxrtl_attr_set attrs, const char *name); + +// Retrieve a string valued attribute from an attribute set. The returned string is zero-terminated. +// +// This function asserts that `cxxrtl_attr_type(attrs, name) == CXXRTL_ATTR_STRING`. If assertions +// are disabled, returns NULL if the attribute is missing or has an incorrect type. +const char *cxxrtl_attr_get_string(cxxrtl_attr_set attrs, const char *name); + +// Retrieve a double precision floating point valued attribute from an attribute set. +// +// This function asserts that `cxxrtl_attr_type(attrs, name) == CXXRTL_ATTR_DOUBLE`. If assertions +// are disabled, returns NULL if the attribute is missing or has an incorrect type. +double cxxrtl_attr_get_double(cxxrtl_attr_set attrs, const char *name); + #ifdef __cplusplus } #endif From 672375ed02be68733856e616a5f4fbf281fe7733 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 26 Oct 2023 00:14:46 +0000 Subject: [PATCH 144/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b89c87ae943..670d44d32d7 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34+43 +YOSYS_VER := 0.34+55 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From f9ab6e147a2c70eb826119235ee34fbe713624d8 Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Mon, 30 Oct 2023 16:30:34 +0100 Subject: [PATCH 145/173] mem: only import attributes from ports if the memory doesn't have them yet --- kernel/mem.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/kernel/mem.cc b/kernel/mem.cc index 40345b81df1..01c866770f5 100644 --- a/kernel/mem.cc +++ b/kernel/mem.cc @@ -149,7 +149,8 @@ void Mem::emit() { wr_port_xlat.push_back(i); for (auto &port : rd_ports) { for (auto attr: port.attributes) - cell->attributes.insert(attr); + if (!cell->has_attribute(attr.first)) + cell->attributes.insert(attr); if (port.cell) { module->remove(port.cell); port.cell = nullptr; @@ -213,7 +214,8 @@ void Mem::emit() { cell->setPort(ID::RD_DATA, rd_data); for (auto &port : wr_ports) { for (auto attr: port.attributes) - cell->attributes.insert(attr); + if (!cell->has_attribute(attr.first)) + cell->attributes.insert(attr); if (port.cell) { module->remove(port.cell); port.cell = nullptr; @@ -251,7 +253,8 @@ void Mem::emit() { cell->setPort(ID::WR_DATA, wr_data); for (auto &init : inits) { for (auto attr: init.attributes) - cell->attributes.insert(attr); + if (!cell->has_attribute(attr.first)) + cell->attributes.insert(attr); if (init.cell) { module->remove(init.cell); init.cell = nullptr; From 4eb18e1f07cc24a7beabac83e862e0f236afbf97 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 1 Nov 2023 08:13:27 +0100 Subject: [PATCH 146/173] change verific log callback api --- frontends/verific/verific.cc | 4 ++-- kernel/log.cc | 2 +- kernel/log.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 115a42e332b..cc9b35e39bc 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -115,7 +115,7 @@ void msg_func(msg_type_t msg_type, const char *message_id, linefile_type linefil if (log_verific_callback) { string full_message = stringf("%s%s\n", message_prefix.c_str(), message.c_str()); - log_verific_callback(int(msg_type), message_id, LineFile::GetFileName(linefile), LineFile::GetLineNo(linefile), full_message.c_str()); + log_verific_callback(int(msg_type), message_id, LineFile::GetFileName(linefile), linefile->GetLeftLine(), linefile->GetLeftCol(), linefile->GetRightLine(), linefile->GetRightCol(), full_message.c_str()); } else { if (msg_type == VERIFIC_ERROR || msg_type == VERIFIC_WARNING || msg_type == VERIFIC_PROGRAM_ERROR) log_warning_noprefix("%s%s\n", message_prefix.c_str(), message.c_str()); @@ -126,7 +126,7 @@ void msg_func(msg_type_t msg_type, const char *message_id, linefile_type linefil verific_error_msg = message; } -void set_verific_logging(void (*cb)(int msg_type, const char *message_id, const char* file_path, unsigned int line_no, const char *msg)) +void set_verific_logging(void (*cb)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg)) { Message::SetConsoleOutput(0); Message::RegisterCallBackMsg(msg_func); diff --git a/kernel/log.cc b/kernel/log.cc index 73e7f16eca5..9a61e8f08b3 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -59,7 +59,7 @@ bool log_quiet_warnings = false; int log_verbose_level; string log_last_error; void (*log_error_atexit)() = NULL; -void (*log_verific_callback)(int msg_type, const char *message_id, const char* file_path, unsigned int line_no, const char *msg) = NULL; +void (*log_verific_callback)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg) = NULL; int log_make_debug = 0; int log_force_debug = 0; diff --git a/kernel/log.h b/kernel/log.h index 78a2e434c7a..e4f06c69d19 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -131,8 +131,8 @@ void log_header(RTLIL::Design *design, const char *format, ...) YS_ATTRIBUTE(for void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); void log_experimental(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); -void set_verific_logging(void (*cb)(int msg_type, const char *message_id, const char* file_path, unsigned int line_no, const char *msg)); -extern void (*log_verific_callback)(int msg_type, const char *message_id, const char* file_path, unsigned int line_no, const char *msg); +void set_verific_logging(void (*cb)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg)); +extern void (*log_verific_callback)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg); // Log with filename to report a problem in a source file. void log_file_warning(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4)); From f06d56d2243272d5f56813f9d07125bfb4d4ab7c Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 3 Nov 2023 08:06:16 +0100 Subject: [PATCH 147/173] Handling non-existing location in verific logs --- frontends/verific/verific.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index cc9b35e39bc..3e73462f120 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -115,7 +115,9 @@ void msg_func(msg_type_t msg_type, const char *message_id, linefile_type linefil if (log_verific_callback) { string full_message = stringf("%s%s\n", message_prefix.c_str(), message.c_str()); - log_verific_callback(int(msg_type), message_id, LineFile::GetFileName(linefile), linefile->GetLeftLine(), linefile->GetLeftCol(), linefile->GetRightLine(), linefile->GetRightCol(), full_message.c_str()); + log_verific_callback(int(msg_type), message_id, LineFile::GetFileName(linefile), + linefile ? linefile->GetLeftLine() : 0, linefile ? linefile->GetLeftCol() : 0, + linefile ? linefile->GetRightLine() : 0, linefile ? linefile->GetRightCol() : 0, full_message.c_str()); } else { if (msg_type == VERIFIC_ERROR || msg_type == VERIFIC_WARNING || msg_type == VERIFIC_PROGRAM_ERROR) log_warning_noprefix("%s%s\n", message_prefix.c_str(), message.c_str()); From 32082477b50aaeb89101249daa52d9de48d3237b Mon Sep 17 00:00:00 2001 From: Lofty Date: Thu, 2 Nov 2023 19:05:41 +0000 Subject: [PATCH 148/173] ice40, ecp5: enable ABC9 by default --- techlibs/ecp5/synth_ecp5.cc | 12 ++++++++---- techlibs/ice40/synth_ice40.cc | 12 ++++++++---- tests/arch/ecp5/add_sub.ys | 7 +++++-- tests/arch/ecp5/counter.ys | 3 ++- tests/arch/ice40/add_sub.ys | 2 +- tests/arch/ice40/mux.ys | 8 ++++---- 6 files changed, 28 insertions(+), 16 deletions(-) diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index fdc36e55267..f6215987f7f 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -93,8 +93,8 @@ struct SynthEcp5Pass : public ScriptPass log(" -abc2\n"); log(" run two passes of 'abc' for slightly improved logic density\n"); log("\n"); - log(" -abc9\n"); - log(" use new ABC9 flow (EXPERIMENTAL)\n"); + log(" -noabc9\n"); + log(" disable use of new ABC9 flow\n"); log("\n"); log(" -vpr\n"); log(" generate an output netlist (and BLIF file) suitable for VPR\n"); @@ -137,7 +137,7 @@ struct SynthEcp5Pass : public ScriptPass retime = false; abc2 = false; vpr = false; - abc9 = false; + abc9 = true; iopad = false; nodsp = false; no_rw_check = false; @@ -224,7 +224,11 @@ struct SynthEcp5Pass : public ScriptPass continue; } if (args[argidx] == "-abc9") { - abc9 = true; + // removed, ABC9 is on by default. + continue; + } + if (args[argidx] == "-noabc9") { + abc9 = false; continue; } if (args[argidx] == "-iopad") { diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 2ae859efe32..a9982649b35 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -106,8 +106,8 @@ struct SynthIce40Pass : public ScriptPass log(" generate an output netlist (and BLIF file) suitable for VPR\n"); log(" (this feature is experimental and incomplete)\n"); log("\n"); - log(" -abc9\n"); - log(" use new ABC9 flow (EXPERIMENTAL)\n"); + log(" -noabc9\n"); + log(" disable use of new ABC9 flow\n"); log("\n"); log(" -flowmap\n"); log(" use FlowMap LUT techmapping instead of abc (EXPERIMENTAL)\n"); @@ -144,7 +144,7 @@ struct SynthIce40Pass : public ScriptPass noabc = false; abc2 = false; vpr = false; - abc9 = false; + abc9 = true; flowmap = false; device_opt = "hx"; no_rw_check = false; @@ -235,7 +235,11 @@ struct SynthIce40Pass : public ScriptPass continue; } if (args[argidx] == "-abc9") { - abc9 = true; + // removed, ABC9 is on by default. + continue; + } + if (args[argidx] == "-noabc9") { + abc9 = false; continue; } if (args[argidx] == "-dff") { diff --git a/tests/arch/ecp5/add_sub.ys b/tests/arch/ecp5/add_sub.ys index d85ce792ee6..c3ce8c56dae 100644 --- a/tests/arch/ecp5/add_sub.ys +++ b/tests/arch/ecp5/add_sub.ys @@ -4,6 +4,9 @@ proc equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd top # Constrain all select calls below inside the top module -select -assert-count 10 t:LUT4 -select -assert-none t:LUT4 %% t:* %D +select -assert-min 25 t:LUT4 +select -assert-max 26 t:LUT4 +select -assert-count 10 t:PFUMX +select -assert-count 6 t:L6MUX21 +select -assert-none t:LUT4 t:PFUMX t:L6MUX21 %% t:* %D diff --git a/tests/arch/ecp5/counter.ys b/tests/arch/ecp5/counter.ys index e46001ffede..e3f713228c3 100644 --- a/tests/arch/ecp5/counter.ys +++ b/tests/arch/ecp5/counter.ys @@ -5,6 +5,7 @@ flatten equiv_opt -assert -multiclock -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd top # Constrain all select calls below inside the top module +select -assert-count 1 t:LUT4 select -assert-count 4 t:CCU2C select -assert-count 8 t:TRELLIS_FF -select -assert-none t:CCU2C t:TRELLIS_FF %% t:* %D +select -assert-none t:LUT4 t:CCU2C t:TRELLIS_FF %% t:* %D diff --git a/tests/arch/ice40/add_sub.ys b/tests/arch/ice40/add_sub.ys index 578ec080380..74b83b8ee91 100644 --- a/tests/arch/ice40/add_sub.ys +++ b/tests/arch/ice40/add_sub.ys @@ -3,7 +3,7 @@ hierarchy -top top equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd top # Constrain all select calls below inside the top module -select -assert-count 11 t:SB_LUT4 +select -assert-count 10 t:SB_LUT4 select -assert-count 6 t:SB_CARRY select -assert-none t:SB_LUT4 t:SB_CARRY %% t:* %D diff --git a/tests/arch/ice40/mux.ys b/tests/arch/ice40/mux.ys index 2b661fd6b1a..977d6975063 100644 --- a/tests/arch/ice40/mux.ys +++ b/tests/arch/ice40/mux.ys @@ -15,7 +15,7 @@ proc equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux4 # Constrain all select calls below inside the top module -select -assert-count 2 t:SB_LUT4 +select -assert-count 3 t:SB_LUT4 select -assert-none t:SB_LUT4 %% t:* %D @@ -25,7 +25,7 @@ proc equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux8 # Constrain all select calls below inside the top module -select -assert-count 5 t:SB_LUT4 +select -assert-count 6 t:SB_LUT4 select -assert-none t:SB_LUT4 %% t:* %D @@ -35,7 +35,7 @@ proc equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux16 # Constrain all select calls below inside the top module -select -assert-min 11 t:SB_LUT4 -select -assert-max 12 t:SB_LUT4 +select -assert-min 13 t:SB_LUT4 +select -assert-max 14 t:SB_LUT4 select -assert-none t:SB_LUT4 %% t:* %D From ea91f189a3db214fbb5c747ca1e6a24b7c3e5494 Mon Sep 17 00:00:00 2001 From: anonkey <6380129+anonkey@users.noreply.github.com> Date: Mon, 2 Oct 2023 17:18:33 +0200 Subject: [PATCH 149/173] cli(tcl): add ability to pass argument to tcl script from cli --- CHANGELOG | 4 ++++ kernel/driver.cc | 52 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ee5f6b43d25..eac68b1ed6d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,10 @@ List of major changes and improvements between releases Yosys 0.34 .. Yosys 0.35-dev -------------------------- +* New commands and options + - Added option "--" to pass arguments down to tcl when using -c option. + - Added ability on MacOS and Windows to pass options after arguments on cli. + Yosys 0.33 .. Yosys 0.34 -------------------------- diff --git a/kernel/driver.cc b/kernel/driver.cc index ef8e7792473..661400e7aff 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -49,39 +49,47 @@ # include #endif -#if !defined(_WIN32) || defined(__MINGW32__) -# include -#else char *optarg; -int optind = 1, optcur = 1; +int optind = 1, optcur = 1, optopt = 0; int getopt(int argc, char **argv, const char *optstring) { - if (optind >= argc || argv[optind][0] != '-') + if (optind >= argc) return -1; + if (argv[optind][0] != '-') { + optopt = 1; + optarg = argv[optind++]; + return optopt; + } + bool takes_arg = false; - int opt = argv[optind][optcur]; + optopt = argv[optind][optcur]; + + if (optopt == '-') { + ++optind; + return -1; + } + for (int i = 0; optstring[i]; i++) - if (opt == optstring[i] && optstring[i + 1] == ':') + if (optopt == optstring[i] && optstring[i + 1] == ':') takes_arg = true; if (!takes_arg) { if (argv[optind][++optcur] == 0) optind++, optcur = 1; - return opt; + return optopt; } if (argv[optind][++optcur]) { optarg = argv[optind++] + optcur; optcur = 1; - return opt; + return optopt; } optarg = argv[++optind]; optind++, optcur = 1; - return opt; + return optopt; } -#endif USING_YOSYS_NAMESPACE @@ -215,6 +223,7 @@ int main(int argc, char **argv) std::string backend_command = "auto"; std::vector vlog_defines; std::vector passes_commands; + std::vector frontend_files; std::vector plugin_filenames; std::string output_filename = ""; std::string scriptfile = ""; @@ -509,6 +518,9 @@ int main(int argc, char **argv) case 'C': run_tcl_shell = true; break; + case '\001': + frontend_files.push_back(optarg); + break; default: fprintf(stderr, "Run '%s -h' for help.\n", argv[0]); exit(1); @@ -561,17 +573,27 @@ int main(int argc, char **argv) run_pass(vdef_cmd); } - while (optind < argc) - if (run_frontend(argv[optind++], frontend_command)) + for (auto it = frontend_files.begin(); it != frontend_files.end(); ++it) { + if (run_frontend((*it).c_str(), frontend_command)) run_shell = false; + } if (!topmodule.empty()) run_pass("hierarchy -top " + topmodule); - if (!scriptfile.empty()) { if (scriptfile_tcl) { #ifdef YOSYS_ENABLE_TCL - if (Tcl_EvalFile(yosys_get_tcl_interp(), scriptfile.c_str()) != TCL_OK) + int tcl_argc = argc - optind; + std::vector script_args; + Tcl_Interp *interp = yosys_get_tcl_interp(); + for (int i = optind; i < argc; ++i) + script_args.push_back(Tcl_NewStringObj(argv[i], strlen(argv[i]))); + + Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argc", 4), NULL, Tcl_NewIntObj(tcl_argc), 0); + Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv", 4), NULL, Tcl_NewListObj(tcl_argc, script_args.data()), 0); + Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv0", 5), NULL, Tcl_NewStringObj(scriptfile.c_str(), scriptfile.length()), 0); + + if (Tcl_EvalFile(interp, scriptfile.c_str()) != TCL_OK) log_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_get_tcl_interp())); #else log_error("Can't exectue TCL script: this version of yosys is not built with TCL support enabled.\n"); From b8b47f7c6c191e14ce350c7fcd579a88fdc3fd26 Mon Sep 17 00:00:00 2001 From: Lofty Date: Fri, 3 Nov 2023 14:52:52 +0000 Subject: [PATCH 150/173] Revert "ice40, ecp5: enable ABC9 by default" --- techlibs/ecp5/synth_ecp5.cc | 12 ++++-------- techlibs/ice40/synth_ice40.cc | 12 ++++-------- tests/arch/ecp5/add_sub.ys | 7 ++----- tests/arch/ecp5/counter.ys | 3 +-- tests/arch/ice40/add_sub.ys | 2 +- tests/arch/ice40/mux.ys | 8 ++++---- 6 files changed, 16 insertions(+), 28 deletions(-) diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index f6215987f7f..fdc36e55267 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -93,8 +93,8 @@ struct SynthEcp5Pass : public ScriptPass log(" -abc2\n"); log(" run two passes of 'abc' for slightly improved logic density\n"); log("\n"); - log(" -noabc9\n"); - log(" disable use of new ABC9 flow\n"); + log(" -abc9\n"); + log(" use new ABC9 flow (EXPERIMENTAL)\n"); log("\n"); log(" -vpr\n"); log(" generate an output netlist (and BLIF file) suitable for VPR\n"); @@ -137,7 +137,7 @@ struct SynthEcp5Pass : public ScriptPass retime = false; abc2 = false; vpr = false; - abc9 = true; + abc9 = false; iopad = false; nodsp = false; no_rw_check = false; @@ -224,11 +224,7 @@ struct SynthEcp5Pass : public ScriptPass continue; } if (args[argidx] == "-abc9") { - // removed, ABC9 is on by default. - continue; - } - if (args[argidx] == "-noabc9") { - abc9 = false; + abc9 = true; continue; } if (args[argidx] == "-iopad") { diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index a9982649b35..2ae859efe32 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -106,8 +106,8 @@ struct SynthIce40Pass : public ScriptPass log(" generate an output netlist (and BLIF file) suitable for VPR\n"); log(" (this feature is experimental and incomplete)\n"); log("\n"); - log(" -noabc9\n"); - log(" disable use of new ABC9 flow\n"); + log(" -abc9\n"); + log(" use new ABC9 flow (EXPERIMENTAL)\n"); log("\n"); log(" -flowmap\n"); log(" use FlowMap LUT techmapping instead of abc (EXPERIMENTAL)\n"); @@ -144,7 +144,7 @@ struct SynthIce40Pass : public ScriptPass noabc = false; abc2 = false; vpr = false; - abc9 = true; + abc9 = false; flowmap = false; device_opt = "hx"; no_rw_check = false; @@ -235,11 +235,7 @@ struct SynthIce40Pass : public ScriptPass continue; } if (args[argidx] == "-abc9") { - // removed, ABC9 is on by default. - continue; - } - if (args[argidx] == "-noabc9") { - abc9 = false; + abc9 = true; continue; } if (args[argidx] == "-dff") { diff --git a/tests/arch/ecp5/add_sub.ys b/tests/arch/ecp5/add_sub.ys index c3ce8c56dae..d85ce792ee6 100644 --- a/tests/arch/ecp5/add_sub.ys +++ b/tests/arch/ecp5/add_sub.ys @@ -4,9 +4,6 @@ proc equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd top # Constrain all select calls below inside the top module -select -assert-min 25 t:LUT4 -select -assert-max 26 t:LUT4 -select -assert-count 10 t:PFUMX -select -assert-count 6 t:L6MUX21 -select -assert-none t:LUT4 t:PFUMX t:L6MUX21 %% t:* %D +select -assert-count 10 t:LUT4 +select -assert-none t:LUT4 %% t:* %D diff --git a/tests/arch/ecp5/counter.ys b/tests/arch/ecp5/counter.ys index e3f713228c3..e46001ffede 100644 --- a/tests/arch/ecp5/counter.ys +++ b/tests/arch/ecp5/counter.ys @@ -5,7 +5,6 @@ flatten equiv_opt -assert -multiclock -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd top # Constrain all select calls below inside the top module -select -assert-count 1 t:LUT4 select -assert-count 4 t:CCU2C select -assert-count 8 t:TRELLIS_FF -select -assert-none t:LUT4 t:CCU2C t:TRELLIS_FF %% t:* %D +select -assert-none t:CCU2C t:TRELLIS_FF %% t:* %D diff --git a/tests/arch/ice40/add_sub.ys b/tests/arch/ice40/add_sub.ys index 74b83b8ee91..578ec080380 100644 --- a/tests/arch/ice40/add_sub.ys +++ b/tests/arch/ice40/add_sub.ys @@ -3,7 +3,7 @@ hierarchy -top top equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd top # Constrain all select calls below inside the top module -select -assert-count 10 t:SB_LUT4 +select -assert-count 11 t:SB_LUT4 select -assert-count 6 t:SB_CARRY select -assert-none t:SB_LUT4 t:SB_CARRY %% t:* %D diff --git a/tests/arch/ice40/mux.ys b/tests/arch/ice40/mux.ys index 977d6975063..2b661fd6b1a 100644 --- a/tests/arch/ice40/mux.ys +++ b/tests/arch/ice40/mux.ys @@ -15,7 +15,7 @@ proc equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux4 # Constrain all select calls below inside the top module -select -assert-count 3 t:SB_LUT4 +select -assert-count 2 t:SB_LUT4 select -assert-none t:SB_LUT4 %% t:* %D @@ -25,7 +25,7 @@ proc equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux8 # Constrain all select calls below inside the top module -select -assert-count 6 t:SB_LUT4 +select -assert-count 5 t:SB_LUT4 select -assert-none t:SB_LUT4 %% t:* %D @@ -35,7 +35,7 @@ proc equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux16 # Constrain all select calls below inside the top module -select -assert-min 13 t:SB_LUT4 -select -assert-max 14 t:SB_LUT4 +select -assert-min 11 t:SB_LUT4 +select -assert-max 12 t:SB_LUT4 select -assert-none t:SB_LUT4 %% t:* %D From 6f1ca68712e7713952440a36b25a9b6848f1a749 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 4 Nov 2023 00:14:46 +0000 Subject: [PATCH 151/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 670d44d32d7..ca822a58592 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34+55 +YOSYS_VER := 0.34+60 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 72c6a01e6743d21937cf407abe19a75850f8a9d4 Mon Sep 17 00:00:00 2001 From: Philippe Sauter Date: Mon, 6 Nov 2023 14:01:37 +0100 Subject: [PATCH 152/173] peepopt: Add initial `shiftadd` pattern --- passes/pmgen/Makefile.inc | 1 + passes/pmgen/peepopt.cc | 1 + passes/pmgen/peepopt_shiftadd.pmg | 116 ++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 passes/pmgen/peepopt_shiftadd.pmg diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index c2257b72083..884e1252224 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -44,6 +44,7 @@ $(eval $(call add_extra_objs,passes/pmgen/peepopt_pm.h)) PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul_right.pmg PEEPOPT_PATTERN += passes/pmgen/peepopt_shiftmul_left.pmg +PEEPOPT_PATTERN += passes/pmgen/peepopt_shiftadd.pmg PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index aef464d79c9..b4394dfd4b5 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -72,6 +72,7 @@ struct PeepoptPass : public Pass { pm.setup(module->selected_cells()); + pm.run_shiftadd(); pm.run_shiftmul_right(); pm.run_shiftmul_left(); pm.run_muldiv(); diff --git a/passes/pmgen/peepopt_shiftadd.pmg b/passes/pmgen/peepopt_shiftadd.pmg new file mode 100644 index 00000000000..1723104996f --- /dev/null +++ b/passes/pmgen/peepopt_shiftadd.pmg @@ -0,0 +1,116 @@ +pattern shiftadd +// +// Transforms add/sub+shift pairs that result from expressions such as data[s*W +C +:W2] +// specifically something like: out[W2-1:0] = data >> (s*W +C) +// will be transformed into: out[W2-1:0] = (data >> C) >> (s*W) +// this can then be optimized using peepopt_shiftmul_right.pmg +// + +match shift + select shift->type.in($shift, $shiftx, $shr) + filter !port(shift, \B).empty() +endmatch + +// the right shift amount +state shift_amount +// log2 scale factor in interpreting of shift_amount +// due to zero padding on the shift cell's B port +state log2scale +// zeros at the MSB position make it unsigned +state msb_zeros + +code shift_amount log2scale msb_zeros + shift_amount = port(shift, \B); + + log2scale = 0; + while (shift_amount[0] == State::S0) { + shift_amount.remove(0); + if (shift_amount.empty()) reject; + log2scale++; + } + + msb_zeros = 0; + while (shift_amount.bits().back() == State::S0) { + msb_zeros = true; + shift_amount.remove(GetSize(shift_amount) - 1); + if (shift_amount.empty()) reject; + } + + if (GetSize(shift_amount) > 20) + reject; +endcode + +state add_var +state add_const +state is_sub +state varport_A + +match add + // either data[var+c +:W1] or data[var-c +:W1] + select add->type.in($add, $sub) + index port(add, \Y) === shift_amount + + // one must be constant, the other is variable + choice constport {\A, \B} + filter port(add, constport).is_fully_const() + define varport (constport == \A ? \B : \A) + + set is_sub add->type.in($sub) + set varport_A (varport == \A) + + // (var+c)< (var<getPort(varport) +endmatch + +code +{ + log_debug("shiftadd candidate in %s: shift=%s, add/sub=%s\n", log_id(module), log_id(shift), log_id(add)); + if (add_const.empty() || GetSize(add_const) > 20) + reject; + + int offset = add_const.as_int() * ( (is_sub && varport_A) ? -1 : 1 ); + bool varport_signed = (varport_A && param(add, \A_SIGNED).as_bool()) \ + || (!varport_A && param(add, \B_SIGNED).as_bool()); + + // data[...-c +:W1] is fine for +/-var (pad at LSB, all data still accessible) + // data[...+c +:W1] is only fine for +var(add) and var unsigned + // (+c cuts lower C bits, making them inaccessible, a signed var could try to access them) + // -> data[c-var +:W1] is illegal + if (is_sub && !varport_A) + reject; + // -> data[var+c +:W1] (with var signed) is illegal + if ( (offset>0) && varport_signed ) + reject; + + did_something = true; + log("shiftadd pattern in %s: shift=%s, add/sub=%s, offset: %d\n", \ + log_id(module), log_id(shift), log_id(add), offset); + + SigSpec old_a = port(shift, \A), new_a; + if(offset<0) { + // data >> (...-c) transformed to {data, c'X} >> (...) + SigSpec padding( (shift->type.in($shiftx) ? State::Sx : State::S0), -offset ); + new_a.append(padding); + new_a.append(old_a); + } else { + // data >> (...+c) transformed to data[MAX:c] >> (...) + new_a.append(old_a.extract(offset, GetSize(old_a)-1-offset)); + + } + + SigSpec new_b = {add_var, SigSpec(State::S0, log2scale)}; + if (msb_zeros || !varport_signed) + new_b.append(State::S0); + + shift->setPort(\A, new_a); + shift->setParam(\A_WIDTH, GetSize(new_a)); + shift->setPort(\B, new_b); + shift->setParam(\B_WIDTH, GetSize(new_b)); + blacklist(add); + accept; +} +endcode From 9ca57d9f1312ccd8cd889031805afdb434ca46f2 Mon Sep 17 00:00:00 2001 From: phsauter Date: Mon, 6 Nov 2023 14:01:37 +0100 Subject: [PATCH 153/173] peepopt: fix and refactor `shiftadd` - moved all selection and filtering logic to the match block - applied less-verbose code suggestions - removed constraint on number of bits in shift-amount - added check for possible wrap-arround in the operation --- passes/pmgen/peepopt_shiftadd.pmg | 70 ++++++++++++++++--------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/passes/pmgen/peepopt_shiftadd.pmg b/passes/pmgen/peepopt_shiftadd.pmg index 1723104996f..25f0756da8e 100644 --- a/passes/pmgen/peepopt_shiftadd.pmg +++ b/passes/pmgen/peepopt_shiftadd.pmg @@ -35,15 +35,12 @@ code shift_amount log2scale msb_zeros shift_amount.remove(GetSize(shift_amount) - 1); if (shift_amount.empty()) reject; } - - if (GetSize(shift_amount) > 20) - reject; endcode -state add_var -state add_const -state is_sub -state varport_A +state var_signed +state var_signal +// offset: signed constant value c in data[var+c +:W1] (constant shift-right amount) +state offset match add // either data[var+c +:W1] or data[var-c +:W1] @@ -52,39 +49,46 @@ match add // one must be constant, the other is variable choice constport {\A, \B} - filter port(add, constport).is_fully_const() + select !port(add, constport).empty() + select port(add, constport).is_fully_const() define varport (constport == \A ? \B : \A) - set is_sub add->type.in($sub) - set varport_A (varport == \A) + // if a value of var is able to wrap the output, the transformation might give wrong results + // an addition/substraction can at most flip one more bit than the largest operand (the carry bit) + // as long as the output can show this bit, no wrap should occur (assuming all signed-ness make sense) + select ( GetSize(port(add, \Y)) > max(GetSize(port(add, \A)), GetSize(port(add, \B))) ) - // (var+c)< (var< varport_A (varport == \A) + define is_sub add->type.in($sub) - // get add_var unmapped (so no `port()` shorthand) - // to attach it to the transformed shift cells \B port - set add_var add->getPort(varport) -endmatch - -code -{ - log_debug("shiftadd candidate in %s: shift=%s, add/sub=%s\n", log_id(module), log_id(shift), log_id(add)); - if (add_const.empty() || GetSize(add_const) > 20) - reject; - - int offset = add_const.as_int() * ( (is_sub && varport_A) ? -1 : 1 ); - bool varport_signed = (varport_A && param(add, \A_SIGNED).as_bool()) \ - || (!varport_A && param(add, \B_SIGNED).as_bool()); + define constport_signed param(add, !varport_A ? \A_SIGNED : \B_SIGNED).as_bool() + define varport_signed param(add, varport_A ? \A_SIGNED : \B_SIGNED).as_bool(); + define offset_negative ((port(add, constport).bits().back() == State::S1) ^ (is_sub && varport_A)) + // checking some value boundaries as well: // data[...-c +:W1] is fine for +/-var (pad at LSB, all data still accessible) // data[...+c +:W1] is only fine for +var(add) and var unsigned // (+c cuts lower C bits, making them inaccessible, a signed var could try to access them) - // -> data[c-var +:W1] is illegal - if (is_sub && !varport_A) - reject; + // either its an add or the variable port is A (it must be positive) + select (add->type.in($add) || varport == \A) + // -> data[var+c +:W1] (with var signed) is illegal - if ( (offset>0) && varport_signed ) + filter !(!offset_negative && varport_signed) + + // state-variables are assigned at the end only: + // shift the log2scale offset in-front of add to get true value: (var+c)< (var<getPort(varport) +endmatch + +code +{ + if (offset>0 && var_signed) { + log("I should not be here %x\n", var_signed); reject; + } did_something = true; log("shiftadd pattern in %s: shift=%s, add/sub=%s, offset: %d\n", \ @@ -98,12 +102,12 @@ code new_a.append(old_a); } else { // data >> (...+c) transformed to data[MAX:c] >> (...) - new_a.append(old_a.extract(offset, GetSize(old_a)-1-offset)); + new_a.append(old_a.extract_end(offset)); } - SigSpec new_b = {add_var, SigSpec(State::S0, log2scale)}; - if (msb_zeros || !varport_signed) + SigSpec new_b = {var_signal, SigSpec(State::S0, log2scale)}; + if (msb_zeros || !var_signed) new_b.append(State::S0); shift->setPort(\A, new_a); From b6df900bcc97beb190207f69475fdfada1d94229 Mon Sep 17 00:00:00 2001 From: Philippe Sauter Date: Mon, 6 Nov 2023 14:01:37 +0100 Subject: [PATCH 154/173] peepopt: Describe `shiftadd` rule in help message --- passes/pmgen/peepopt.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index b4394dfd4b5..edd3b18a815 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -48,6 +48,9 @@ struct PeepoptPass : public Pass { log(" Analogously, replace A<<(B*C) with appropriate selection of\n"); log(" output bits from A<<(B<>(B+D) with (A'>>D)>>(B) where D is constant and\n"); + log(" A' is derived from A by padding or cutting inaccessible bits.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { From c3b8de54dae39a67046875dbc540da59bc45d342 Mon Sep 17 00:00:00 2001 From: phsauter Date: Mon, 6 Nov 2023 14:01:37 +0100 Subject: [PATCH 155/173] test: add tests for `shiftadd` and `shiftmul` This expands the part-select tests with one additional module. It specifically tests the different variants of the `peepopt` optimizations `shiftadd` and `shiftmul`. Not all these cases are actually transformed using `shiftadd`, including them also checks if the correct variants are rejected. --- tests/simple/partsel.v | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/simple/partsel.v b/tests/simple/partsel.v index 5e9730d6bd1..722ed7b1bd9 100644 --- a/tests/simple/partsel.v +++ b/tests/simple/partsel.v @@ -110,3 +110,42 @@ module partsel_test007 ( dout[n+1] = din[n]; end endmodule + + +module partsel_test008 ( + input [127:0] din, + input [3:0] idx, + input [4:0] uoffset, + input signed [4:0] soffset, + output [ 7:0] dout0, + output [ 7:0] dout1, + output [ 7:0] dout2, + output [ 7:0] dout3, + output [ 3:0] dout4, + output [ 3:0] dout5, + output [ 3:0] dout6, + output [ 3:0] dout7, + output [ 3:0] dout8, + output [11:0] dout9, + output [11:0] dout10, + output [11:0] dout11 +); + +// common: block-select with offsets +assign dout0 = din[idx*8 +uoffset +:8]; +assign dout1 = din[idx*8 -uoffset +:8]; +assign dout2 = din[idx*8 +soffset +:8]; +assign dout3 = din[idx*8 -soffset +:8]; + +// only partial block used +assign dout4 = din[idx*8 +uoffset +:4]; +assign dout5 = din[idx*8 -uoffset +:4]; +assign dout6 = din[idx*8 +soffset +:4]; +assign dout7 = din[idx*8 -soffset +:4]; + +// uncommon: more than one block used +assign dout8 = din[idx*8 +uoffset +:12]; +assign dout9 = din[idx*8 -uoffset +:12]; +assign dout10 = din[idx*8 +soffset +:12]; +assign dout11 = din[idx*8 -soffset +:12]; +endmodule From 3618294bacbb5b3a2514e5ef69effb0f82c321af Mon Sep 17 00:00:00 2001 From: phsauter Date: Mon, 6 Nov 2023 16:35:00 +0100 Subject: [PATCH 156/173] peepopt: Add assert of consistent `shiftadd` data --- passes/pmgen/peepopt_shiftadd.pmg | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/passes/pmgen/peepopt_shiftadd.pmg b/passes/pmgen/peepopt_shiftadd.pmg index 25f0756da8e..f9c930eae3d 100644 --- a/passes/pmgen/peepopt_shiftadd.pmg +++ b/passes/pmgen/peepopt_shiftadd.pmg @@ -85,10 +85,11 @@ endmatch code { - if (offset>0 && var_signed) { - log("I should not be here %x\n", var_signed); - reject; - } + // positive constant offset with a signed variable (index) cannot be handled + // the above filter should get rid of this case but 'offset' is calculated differently + // due to limitations of state-variables in pmgen + // it should only differ if previous passes create invalid data + log_assert(!(offset>0 && var_signed)); did_something = true; log("shiftadd pattern in %s: shift=%s, add/sub=%s, offset: %d\n", \ From d415b4d98a0ac7d5177e3b5844477e8460bfa862 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Mon, 6 Nov 2023 16:40:13 +0100 Subject: [PATCH 157/173] cli: Cleanups for tcl argument handling * Keep the previous behavior when no tcl script is used * Do not treat "-" as a flag but as a positional argument * Keep including as it's also used for other functions (at least for the emscripten build) * Move the custom getopt implementation into the Yosys namespace to avoid potential collisions --- kernel/driver.cc | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/kernel/driver.cc b/kernel/driver.cc index 661400e7aff..c779611e097 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -49,6 +49,12 @@ # include #endif +#if !defined(_WIN32) || defined(__MINGW32__) +# include +#endif + +USING_YOSYS_NAMESPACE + char *optarg; int optind = 1, optcur = 1, optopt = 0; int getopt(int argc, char **argv, const char *optstring) @@ -56,7 +62,7 @@ int getopt(int argc, char **argv, const char *optstring) if (optind >= argc) return -1; - if (argv[optind][0] != '-') { + if (argv[optind][0] != '-' || argv[optind][1] == 0) { optopt = 1; optarg = argv[optind++]; return optopt; @@ -91,9 +97,6 @@ int getopt(int argc, char **argv, const char *optstring) return optopt; } - -USING_YOSYS_NAMESPACE - #ifdef EMSCRIPTEN # include # include @@ -573,6 +576,12 @@ int main(int argc, char **argv) run_pass(vdef_cmd); } + if (scriptfile.empty() || !scriptfile_tcl) { + // Without a TCL script, arguments following '--' are also treated as frontend files + for (int i = optind; i < argc; ++i) + frontend_files.push_back(argv[i]); + } + for (auto it = frontend_files.begin(); it != frontend_files.end(); ++it) { if (run_frontend((*it).c_str(), frontend_command)) run_shell = false; From cc31c6ebc450f0dfe991663376c4e0b94944188b Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 7 Nov 2023 08:45:31 +0100 Subject: [PATCH 158/173] Release version 0.35 --- CHANGELOG | 10 +++++++++- Makefile | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ee5f6b43d25..528ca2a32c0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,8 +2,16 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.34 .. Yosys 0.35-dev +Yosys 0.34 .. Yosys 0.35 -------------------------- + * Various + - Improvements on "peepopt" shiftmul matcher. + - Improvements on "ram_style" attributes handling. + + * Verific support + - Improved static elaboration for VHDL and mixed HDL designs. + - Expose "hdlname" attribute with original module name. + - Expose "architecture" attribute with VHDL architecture name. Yosys 0.33 .. Yosys 0.34 -------------------------- diff --git a/Makefile b/Makefile index ca822a58592..0de05b62203 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34+60 +YOSYS_VER := 0.35 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -157,7 +157,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 4a1b559.. | wc -l`/;" Makefile +# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 4a1b559.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # From 8808da243ba68af2fb22b311beef83111089ec77 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 7 Nov 2023 08:47:34 +0100 Subject: [PATCH 159/173] Next dev cycle --- CHANGELOG | 3 +++ Makefile | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 528ca2a32c0..57abcbab26e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,9 @@ List of major changes and improvements between releases ======================================================= +Yosys 0.35 .. Yosys 0.36-dev +-------------------------- + Yosys 0.34 .. Yosys 0.35 -------------------------- * Various diff --git a/Makefile b/Makefile index 0de05b62203..83ea7a649e7 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.35 +YOSYS_VER := 0.35+0 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -157,7 +157,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: -# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 4a1b559.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline cc31c6e.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # From ee3a4ce14dce584afeba4003232e934488c2701b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 7 Nov 2023 16:21:39 +0100 Subject: [PATCH 160/173] synth_lattice: Merge NOT gates on DFF control signals `dfflegalize` will emit NOT gates to drive control signals on flip-flops when mapping to supported flip-flop polarities. Typically in a design this will produce a number of NOT gates driven by the same signal. For one reason or another ABC doesn't fully cancel this redundancy during LUT mapping. Insert an explicit `opt_merge` pass to improve synthesis QoR. --- techlibs/lattice/synth_lattice.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/techlibs/lattice/synth_lattice.cc b/techlibs/lattice/synth_lattice.cc index e2987d0259e..7ecfb95de7a 100644 --- a/techlibs/lattice/synth_lattice.cc +++ b/techlibs/lattice/synth_lattice.cc @@ -409,6 +409,7 @@ struct SynthLatticePass : public ScriptPass dfflegalize_args += " -cell $_DLATCH_?_ x"; } run("dfflegalize" + dfflegalize_args, "($_ALDFF_*_ only if -asyncprld, $_DLATCH_* only if not -asyncprld, $_*DFFE_* only if not -nodffe)"); + run("opt_merge"); if ((abc9 && dff) || help_mode) run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$_SDFF*", "(only if -abc9 and -dff)"); run("techmap -D NO_LUT -map +/lattice/cells_map.v"); From fed272099958bfc29dadec0ee366d20056171c00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 7 Nov 2023 16:25:20 +0100 Subject: [PATCH 161/173] synth_lattice: Optimize flip-flop memories better After `memory_map` maps memories to flip-flops we need to let `opt` remove undef muxes, otherwise we block enable/reset signal inference by `opt_dff` which is in detriment to QoR. --- techlibs/lattice/synth_lattice.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/lattice/synth_lattice.cc b/techlibs/lattice/synth_lattice.cc index 7ecfb95de7a..738ef0334bd 100644 --- a/techlibs/lattice/synth_lattice.cc +++ b/techlibs/lattice/synth_lattice.cc @@ -373,7 +373,7 @@ struct SynthLatticePass : public ScriptPass { run("opt -fast -mux_undef -undriven -fine"); run("memory_map"); - run("opt -undriven -fine"); + run("opt -undriven -fine -mux_undef"); } if (check_label("map_gates")) From 5691cd095848f89f9f84a29f267fdebe95bae832 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 00:15:30 +0000 Subject: [PATCH 162/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 83ea7a649e7..3e6f05d4e48 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.35+0 +YOSYS_VER := 0.35+7 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 83d2f4f334708ae80592a13dfc71acc416fc1655 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Mon, 13 Nov 2023 16:29:52 +1300 Subject: [PATCH 163/173] techlibs: fix typo in help message --- techlibs/achronix/synth_achronix.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/achronix/synth_achronix.cc b/techlibs/achronix/synth_achronix.cc index 9a0a7a3b57b..2b969182eaf 100644 --- a/techlibs/achronix/synth_achronix.cc +++ b/techlibs/achronix/synth_achronix.cc @@ -26,7 +26,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct SynthAchronixPass : public ScriptPass { - SynthAchronixPass() : ScriptPass("synth_achronix", "synthesis for Acrhonix Speedster22i FPGAs.") { } + SynthAchronixPass() : ScriptPass("synth_achronix", "synthesis for Achronix Speedster22i FPGAs.") { } void help() override { From f7d4a855c66e53d082afc8477ddba46fe1d6d5b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 13 Nov 2023 10:41:31 +0100 Subject: [PATCH 164/173] techlibs: Add `cmp2softlogic.v` to common --- techlibs/common/Makefile.inc | 1 + techlibs/common/cmp2softlogic.v | 117 ++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 techlibs/common/cmp2softlogic.v diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc index 47f1ed60456..6b377855e3e 100644 --- a/techlibs/common/Makefile.inc +++ b/techlibs/common/Makefile.inc @@ -34,3 +34,4 @@ $(eval $(call add_share_file,share,techlibs/common/abc9_model.v)) $(eval $(call add_share_file,share,techlibs/common/abc9_map.v)) $(eval $(call add_share_file,share,techlibs/common/abc9_unmap.v)) $(eval $(call add_share_file,share,techlibs/common/cmp2lcu.v)) +$(eval $(call add_share_file,share,techlibs/common/cmp2softlogic.v)) diff --git a/techlibs/common/cmp2softlogic.v b/techlibs/common/cmp2softlogic.v new file mode 100644 index 00000000000..e480b4eee99 --- /dev/null +++ b/techlibs/common/cmp2softlogic.v @@ -0,0 +1,117 @@ +module constgtge(C, A, B, Y); +parameter A_WIDTH = 0; +parameter B_WIDTH = 0; + +(* force_downto *) +input [A_WIDTH-1:0] A; +(* force_downto *) +input [B_WIDTH-1:0] B; +output Y; +input C; + +wire [A_WIDTH:0] ch; +genvar n; +generate + if (B_WIDTH > A_WIDTH) begin + // Fail + end else begin + assign ch[0] = C; + for (n = 0; n < A_WIDTH; n = n + 1) begin + if (n < B_WIDTH) begin + assign ch[n + 1] = B[n] ? (ch[n] && A[n]) : (ch[n] || A[n]); + end else begin + assign ch[n + 1] = ch[n] || A[n]; + end + end + assign Y = ch[A_WIDTH]; + end +endgenerate +endmodule + +module constltle(C, A, B, Y); +parameter A_WIDTH = 0; +parameter B_WIDTH = 0; + +(* force_downto *) +input [A_WIDTH-1:0] A; +(* force_downto *) +input [B_WIDTH-1:0] B; +output Y; +input C; + +wire [A_WIDTH:0] ch; +genvar n; +generate + if (B_WIDTH > A_WIDTH) begin + // Fail + end else begin + assign ch[0] = C; + for (n = 0; n < A_WIDTH; n = n + 1) begin + if (n < B_WIDTH) begin + assign ch[n + 1] = !B[n] ? (ch[n] && !A[n]) : (ch[n] || !A[n]); + end else begin + assign ch[n + 1] = ch[n] && !A[n]; + end + end + assign Y = ch[A_WIDTH]; + end +endgenerate +endmodule + +(* techmap_celltype = "$ge $gt $le $lt" *) +module _map_const_cmp_(A, B, Y); +parameter A_WIDTH = 0; +parameter B_WIDTH = 0; +parameter Y_WIDTH = 0; +parameter A_SIGNED = 0; +parameter B_SIGNED = 0; + +(* force_downto *) +input [A_WIDTH-1:0] A; +(* force_downto *) +input [B_WIDTH-1:0] B; +(* force_downto *) +output [Y_WIDTH-1:0] Y; + +parameter _TECHMAP_CELLTYPE_ = ""; + +parameter _TECHMAP_CONSTMSK_A_ = 0; +parameter _TECHMAP_CONSTVAL_A_ = 0; +parameter _TECHMAP_CONSTMSK_B_ = 0; +parameter _TECHMAP_CONSTVAL_B_ = 0; + +wire [1023:0] _TECHMAP_DO_ = "opt -fast;"; + +wire [A_WIDTH:0] ch; + +genvar n; +generate + if (Y_WIDTH != 1 || A_SIGNED || B_SIGNED) + wire _TECHMAP_FAIL_ = 1; + else if (&_TECHMAP_CONSTMSK_A_) begin + if (A_WIDTH > B_WIDTH) + wire _TECHMAP_FAIL_ = 1; + else if (_TECHMAP_CELLTYPE_ == "$lt" || _TECHMAP_CELLTYPE_ == "$le") + constgtge #(.A_WIDTH(B_WIDTH), .B_WIDTH(A_WIDTH)) + _TECHMAP_REPLACE_(.A(B), .B(A), .Y(Y), + .C(_TECHMAP_CELLTYPE_ == "$lt")); + else + constltle #(.A_WIDTH(B_WIDTH), .B_WIDTH(A_WIDTH)) + _TECHMAP_REPLACE_(.A(B), .B(A), .Y(Y), + .C(_TECHMAP_CELLTYPE_ == "$gt")); + end else if (&_TECHMAP_CONSTMSK_B_) begin + if (B_WIDTH > A_WIDTH) + wire _TECHMAP_FAIL_ = 1; + else if (_TECHMAP_CELLTYPE_ == "$lt" || _TECHMAP_CELLTYPE_ == "$le") + constltle #(.A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH)) + _TECHMAP_REPLACE_(.A(A), .B(B), .Y(Y), + .C(_TECHMAP_CELLTYPE_ == "$le")); + else + constgtge #(.A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH)) + _TECHMAP_REPLACE_(.A(A), .B(B), .Y(Y), + .C(_TECHMAP_CELLTYPE_ == "$ge")); + end else + wire _TECHMAP_FAIL_ = 1; +endgenerate + +endmodule From 3ffa4b5e5d478b653dba2fd640d6b44f0b92f01c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 13 Nov 2023 10:41:54 +0100 Subject: [PATCH 165/173] synth_lattice: Wire up `cmp2softlogic` as an option --- techlibs/lattice/synth_lattice.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/techlibs/lattice/synth_lattice.cc b/techlibs/lattice/synth_lattice.cc index e2987d0259e..ba39397c472 100644 --- a/techlibs/lattice/synth_lattice.cc +++ b/techlibs/lattice/synth_lattice.cc @@ -127,6 +127,10 @@ struct SynthLatticePass : public ScriptPass log(" read/write collision\" (same result as setting the no_rw_check\n"); log(" attribute on all memories).\n"); log("\n"); + log(" -cmp2softlogic\n"); + log(" implement constant comparisons in soft logic, do not involve\n"); + log(" hard carry chains\n"); + log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); help_script(); @@ -135,6 +139,7 @@ struct SynthLatticePass : public ScriptPass string top_opt, edif_file, json_file, family; bool noccu2, nodffe, nobram, nolutram, nowidelut, asyncprld, flatten, dff, retime, abc2, abc9, iopad, nodsp, no_rw_check, have_dsp; + bool cmp2softlogic; string postfix, arith_map, brams_map, dsp_map; void clear_flags() override @@ -162,6 +167,7 @@ struct SynthLatticePass : public ScriptPass brams_map = ""; dsp_map = ""; have_dsp = false; + cmp2softlogic = false; } void execute(std::vector args, RTLIL::Design *design) override @@ -263,6 +269,10 @@ struct SynthLatticePass : public ScriptPass no_rw_check = true; continue; } + if (args[argidx] == "-cmp2softlogic") { + cmp2softlogic = true; + continue; + } break; } extra_args(args, argidx, design); @@ -343,6 +353,8 @@ struct SynthLatticePass : public ScriptPass run("peepopt"); run("opt_clean"); run("share"); + if (cmp2softlogic) + run("techmap -map +/cmp2softlogic.v"); run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); run("opt_expr"); run("opt_clean"); From 7ae4041e20c9ab794ceb4dbe68021ee11c13049d Mon Sep 17 00:00:00 2001 From: Lofty Date: Mon, 13 Nov 2023 15:12:23 +0000 Subject: [PATCH 166/173] ice40, ecp5, gowin: enable ABC9 by default --- techlibs/ecp5/synth_ecp5.cc | 12 ++++++++---- techlibs/gowin/synth_gowin.cc | 12 ++++++++---- techlibs/ice40/synth_ice40.cc | 10 +++++++--- tests/arch/ecp5/add_sub.ys | 7 +++++-- tests/arch/ecp5/counter.ys | 3 ++- tests/arch/gowin/counter.ys | 3 ++- tests/arch/gowin/init.ys | 2 +- tests/arch/gowin/mux.ys | 9 ++++++++- tests/arch/ice40/add_sub.ys | 2 +- tests/arch/ice40/mux.ys | 8 ++++---- 10 files changed, 46 insertions(+), 22 deletions(-) diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index fdc36e55267..f6215987f7f 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -93,8 +93,8 @@ struct SynthEcp5Pass : public ScriptPass log(" -abc2\n"); log(" run two passes of 'abc' for slightly improved logic density\n"); log("\n"); - log(" -abc9\n"); - log(" use new ABC9 flow (EXPERIMENTAL)\n"); + log(" -noabc9\n"); + log(" disable use of new ABC9 flow\n"); log("\n"); log(" -vpr\n"); log(" generate an output netlist (and BLIF file) suitable for VPR\n"); @@ -137,7 +137,7 @@ struct SynthEcp5Pass : public ScriptPass retime = false; abc2 = false; vpr = false; - abc9 = false; + abc9 = true; iopad = false; nodsp = false; no_rw_check = false; @@ -224,7 +224,11 @@ struct SynthEcp5Pass : public ScriptPass continue; } if (args[argidx] == "-abc9") { - abc9 = true; + // removed, ABC9 is on by default. + continue; + } + if (args[argidx] == "-noabc9") { + abc9 = false; continue; } if (args[argidx] == "-iopad") { diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 3b9d7424a7b..094bd4fc5b1 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -78,8 +78,8 @@ struct SynthGowinPass : public ScriptPass log(" -noalu\n"); log(" do not use ALU cells\n"); log("\n"); - log(" -abc9\n"); - log(" use new ABC9 flow (EXPERIMENTAL)\n"); + log(" -noabc9\n"); + log(" disable use of new ABC9 flow\n"); log("\n"); log(" -no-rw-check\n"); log(" marks all recognized read ports as \"return don't-care value on\n"); @@ -106,7 +106,7 @@ struct SynthGowinPass : public ScriptPass nodffe = false; nolutram = false; nowidelut = false; - abc9 = false; + abc9 = true; noiopads = false; noalu = false; no_rw_check = false; @@ -170,7 +170,11 @@ struct SynthGowinPass : public ScriptPass continue; } if (args[argidx] == "-abc9") { - abc9 = true; + // removed, ABC9 is on by default. + continue; + } + if (args[argidx] == "-abc9") { + abc9 = false; continue; } if (args[argidx] == "-noiopads") { diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 2ae859efe32..7632df73381 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -106,8 +106,8 @@ struct SynthIce40Pass : public ScriptPass log(" generate an output netlist (and BLIF file) suitable for VPR\n"); log(" (this feature is experimental and incomplete)\n"); log("\n"); - log(" -abc9\n"); - log(" use new ABC9 flow (EXPERIMENTAL)\n"); + log(" -noabc9\n"); + log(" disable use of new ABC9 flow\n"); log("\n"); log(" -flowmap\n"); log(" use FlowMap LUT techmapping instead of abc (EXPERIMENTAL)\n"); @@ -144,7 +144,7 @@ struct SynthIce40Pass : public ScriptPass noabc = false; abc2 = false; vpr = false; - abc9 = false; + abc9 = true; flowmap = false; device_opt = "hx"; no_rw_check = false; @@ -235,6 +235,10 @@ struct SynthIce40Pass : public ScriptPass continue; } if (args[argidx] == "-abc9") { + // removed, ABC9 is on by default. + continue; + } + if (args[argidx] == "-noabc9") { abc9 = true; continue; } diff --git a/tests/arch/ecp5/add_sub.ys b/tests/arch/ecp5/add_sub.ys index d85ce792ee6..c3ce8c56dae 100644 --- a/tests/arch/ecp5/add_sub.ys +++ b/tests/arch/ecp5/add_sub.ys @@ -4,6 +4,9 @@ proc equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd top # Constrain all select calls below inside the top module -select -assert-count 10 t:LUT4 -select -assert-none t:LUT4 %% t:* %D +select -assert-min 25 t:LUT4 +select -assert-max 26 t:LUT4 +select -assert-count 10 t:PFUMX +select -assert-count 6 t:L6MUX21 +select -assert-none t:LUT4 t:PFUMX t:L6MUX21 %% t:* %D diff --git a/tests/arch/ecp5/counter.ys b/tests/arch/ecp5/counter.ys index e46001ffede..e3f713228c3 100644 --- a/tests/arch/ecp5/counter.ys +++ b/tests/arch/ecp5/counter.ys @@ -5,6 +5,7 @@ flatten equiv_opt -assert -multiclock -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd top # Constrain all select calls below inside the top module +select -assert-count 1 t:LUT4 select -assert-count 4 t:CCU2C select -assert-count 8 t:TRELLIS_FF -select -assert-none t:CCU2C t:TRELLIS_FF %% t:* %D +select -assert-none t:LUT4 t:CCU2C t:TRELLIS_FF %% t:* %D diff --git a/tests/arch/gowin/counter.ys b/tests/arch/gowin/counter.ys index bdbc7ee2432..ec6ca0f5ee2 100644 --- a/tests/arch/gowin/counter.ys +++ b/tests/arch/gowin/counter.ys @@ -6,10 +6,11 @@ equiv_opt -assert -multiclock -map +/gowin/cells_sim.v synth_gowin # equivalency design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd top # Constrain all select calls below inside the top module +select -assert-count 1 t:LUT1 select -assert-count 8 t:DFFC select -assert-count 8 t:ALU select -assert-count 1 t:GND select -assert-count 1 t:VCC select -assert-count 2 t:IBUF select -assert-count 8 t:OBUF -select -assert-none t:DFFC t:ALU t:GND t:VCC t:IBUF t:OBUF %% t:* %D +select -assert-none t:LUT1 t:DFFC t:ALU t:GND t:VCC t:IBUF t:OBUF %% t:* %D diff --git a/tests/arch/gowin/init.ys b/tests/arch/gowin/init.ys index fba7c2fa583..d522801c63d 100644 --- a/tests/arch/gowin/init.ys +++ b/tests/arch/gowin/init.ys @@ -1,5 +1,5 @@ read_verilog init.v -read_verilog -lib +/gowin/cells_sim.v +read_verilog -lib -specify +/gowin/cells_sim.v design -save read proc diff --git a/tests/arch/gowin/mux.ys b/tests/arch/gowin/mux.ys index 33b092284fa..d5978f4ea5c 100644 --- a/tests/arch/gowin/mux.ys +++ b/tests/arch/gowin/mux.ys @@ -32,10 +32,17 @@ proc equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux8 # Constrain all select calls below inside the top module +select -assert-count 1 t:LUT1 +select -assert-count 10 t:LUT3 +select -assert-count 1 t:LUT4 +select -assert-count 5 t:MUX2_LUT5 +select -assert-count 2 t:MUX2_LUT6 +select -assert-count 1 t:MUX2_LUT7 select -assert-count 11 t:IBUF select -assert-count 1 t:OBUF +select -assert-count 1 t:GND -select -assert-none t:LUT* t:MUX2_LUT6 t:MUX2_LUT5 t:IBUF t:OBUF %% t:* %D +select -assert-none t:LUT* t:MUX2_LUT7 t:MUX2_LUT6 t:MUX2_LUT5 t:IBUF t:OBUF t:GND %% t:* %D design -load read hierarchy -top mux16 diff --git a/tests/arch/ice40/add_sub.ys b/tests/arch/ice40/add_sub.ys index 578ec080380..74b83b8ee91 100644 --- a/tests/arch/ice40/add_sub.ys +++ b/tests/arch/ice40/add_sub.ys @@ -3,7 +3,7 @@ hierarchy -top top equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd top # Constrain all select calls below inside the top module -select -assert-count 11 t:SB_LUT4 +select -assert-count 10 t:SB_LUT4 select -assert-count 6 t:SB_CARRY select -assert-none t:SB_LUT4 t:SB_CARRY %% t:* %D diff --git a/tests/arch/ice40/mux.ys b/tests/arch/ice40/mux.ys index 2b661fd6b1a..977d6975063 100644 --- a/tests/arch/ice40/mux.ys +++ b/tests/arch/ice40/mux.ys @@ -15,7 +15,7 @@ proc equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux4 # Constrain all select calls below inside the top module -select -assert-count 2 t:SB_LUT4 +select -assert-count 3 t:SB_LUT4 select -assert-none t:SB_LUT4 %% t:* %D @@ -25,7 +25,7 @@ proc equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux8 # Constrain all select calls below inside the top module -select -assert-count 5 t:SB_LUT4 +select -assert-count 6 t:SB_LUT4 select -assert-none t:SB_LUT4 %% t:* %D @@ -35,7 +35,7 @@ proc equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux16 # Constrain all select calls below inside the top module -select -assert-min 11 t:SB_LUT4 -select -assert-max 12 t:SB_LUT4 +select -assert-min 13 t:SB_LUT4 +select -assert-max 14 t:SB_LUT4 select -assert-none t:SB_LUT4 %% t:* %D From 46408b5da3a6ca74dc27ddac339529485d3765b7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 14 Nov 2023 00:15:32 +0000 Subject: [PATCH 167/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3e6f05d4e48..04b3a157ee3 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.35+7 +YOSYS_VER := 0.35+21 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 726c501e7ec8e913060fd48df1e07a7b998a179d Mon Sep 17 00:00:00 2001 From: Catherine Date: Tue, 14 Nov 2023 02:03:23 +0000 Subject: [PATCH 168/173] Update WASI compilation flags to include required libraries --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 04b3a157ee3..be0f8ca2e99 100644 --- a/Makefile +++ b/Makefile @@ -321,9 +321,9 @@ AR = $(WASI_SDK)/bin/ar RANLIB = $(WASI_SDK)/bin/ranlib WASIFLAGS := --sysroot $(WASI_SDK)/share/wasi-sysroot $(WASIFLAGS) endif -CXXFLAGS := $(WASIFLAGS) -std=$(CXXSTD) -Os $(filter-out -fPIC,$(CXXFLAGS)) +CXXFLAGS := $(WASIFLAGS) -std=$(CXXSTD) -Os -D_WASI_EMULATED_PROCESS_CLOCKS $(filter-out -fPIC,$(CXXFLAGS)) LDFLAGS := $(WASIFLAGS) -Wl,-z,stack-size=1048576 $(filter-out -rdynamic,$(LDFLAGS)) -LDLIBS := $(filter-out -lrt,$(LDLIBS)) +LDLIBS := -lwasi-emulated-process-clocks $(filter-out -lrt,$(LDLIBS)) ABCMKARGS += AR="$(AR)" RANLIB="$(RANLIB)" ABCMKARGS += ARCHFLAGS="$(WASIFLAGS) -DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING -DABC_NO_RLIMIT -Wno-c++11-narrowing" ABCMKARGS += OPTFLAGS="-Os" From c11744b4efb5fd372efeb90af1c8f5801047f445 Mon Sep 17 00:00:00 2001 From: Catherine Date: Tue, 14 Nov 2023 03:33:35 +0000 Subject: [PATCH 169/173] Fix WASI compilation flags for abc. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index be0f8ca2e99..15e336b88ce 100644 --- a/Makefile +++ b/Makefile @@ -325,7 +325,7 @@ CXXFLAGS := $(WASIFLAGS) -std=$(CXXSTD) -Os -D_WASI_EMULATED_PROCESS_CLOCKS $(fi LDFLAGS := $(WASIFLAGS) -Wl,-z,stack-size=1048576 $(filter-out -rdynamic,$(LDFLAGS)) LDLIBS := -lwasi-emulated-process-clocks $(filter-out -lrt,$(LDLIBS)) ABCMKARGS += AR="$(AR)" RANLIB="$(RANLIB)" -ABCMKARGS += ARCHFLAGS="$(WASIFLAGS) -DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING -DABC_NO_RLIMIT -Wno-c++11-narrowing" +ABCMKARGS += ARCHFLAGS="$(WASIFLAGS) -D_WASI_EMULATED_PROCESS_CLOCKS -DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING -DABC_NO_RLIMIT -Wno-c++11-narrowing" ABCMKARGS += OPTFLAGS="-Os" EXE = .wasm From 309558767d7a67b7f17bfd40335036009017c055 Mon Sep 17 00:00:00 2001 From: Lofty Date: Tue, 14 Nov 2023 22:37:29 +0000 Subject: [PATCH 170/173] gowin: fix typo --- techlibs/gowin/synth_gowin.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 094bd4fc5b1..302ba76e5af 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -173,7 +173,7 @@ struct SynthGowinPass : public ScriptPass // removed, ABC9 is on by default. continue; } - if (args[argidx] == "-abc9") { + if (args[argidx] == "-noabc9") { abc9 = false; continue; } From 7eea047793afcfafe7507d828aeec574f56f8901 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 15 Nov 2023 00:15:49 +0000 Subject: [PATCH 171/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 15e336b88ce..187ebcd8717 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.35+21 +YOSYS_VER := 0.35+24 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 5c96746309e67dfd3d2dfc168d4b3c5c07c34e50 Mon Sep 17 00:00:00 2001 From: Lofty Date: Fri, 17 Nov 2023 12:49:17 +0000 Subject: [PATCH 172/173] ice40: fix -noabc9 --- techlibs/ice40/synth_ice40.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 7632df73381..a9982649b35 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -239,7 +239,7 @@ struct SynthIce40Pass : public ScriptPass continue; } if (args[argidx] == "-noabc9") { - abc9 = true; + abc9 = false; continue; } if (args[argidx] == "-dff") { From ab6c1d368b103addae8cc658659e2f7cfd166d94 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 18 Nov 2023 00:15:31 +0000 Subject: [PATCH 173/173] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 187ebcd8717..d0fa98bea07 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.35+24 +YOSYS_VER := 0.35+29 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo