From b506f398dda108659c6743f322434a63e677e0fc Mon Sep 17 00:00:00 2001 From: gatecat Date: Thu, 25 Nov 2021 19:13:08 +0000 Subject: Add read_liberty -wb Signed-off-by: gatecat --- frontends/liberty/liberty.cc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc index abf8de4d1..188ef2e04 100644 --- a/frontends/liberty/liberty.cc +++ b/frontends/liberty/liberty.cc @@ -464,6 +464,9 @@ struct LibertyFrontend : public Frontend { log(" -lib\n"); log(" only create empty blackbox modules\n"); log("\n"); + log(" -wb\n"); + log(" mark imported cells as whiteboxes\n"); + log("\n"); log(" -nooverwrite\n"); log(" ignore re-definitions of modules. (the default behavior is to\n"); log(" create an error message if the existing module is not a blackbox\n"); @@ -489,6 +492,7 @@ struct LibertyFrontend : public Frontend { void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) override { bool flag_lib = false; + bool flag_wb = false; bool flag_nooverwrite = false; bool flag_overwrite = false; bool flag_ignore_miss_func = false; @@ -505,6 +509,10 @@ struct LibertyFrontend : public Frontend { flag_lib = true; continue; } + if (arg == "-wb") { + flag_wb = true; + continue; + } if (arg == "-ignore_redef" || arg == "-nooverwrite") { flag_nooverwrite = true; flag_overwrite = false; @@ -535,6 +543,9 @@ struct LibertyFrontend : public Frontend { } extra_args(f, filename, args, argidx); + if (flag_wb && flag_lib) + log_error("-wb and -lib cannot be specified together!\n"); + LibertyParser parser(*f); int cell_count = 0; @@ -572,6 +583,9 @@ struct LibertyFrontend : public Frontend { if (flag_lib) module->set_bool_attribute(ID::blackbox); + if (flag_wb) + module->set_bool_attribute(ID::whitebox); + for (auto &attr : attributes) module->attributes[attr] = 1; -- cgit v1.2.3 From 25a4cd7020c100838e359b393ffb545532e69101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Thu, 16 Jun 2022 06:04:04 +0200 Subject: memory_libmap: Fix params emitted for unused ports for consistency. --- passes/memory/memory_libmap.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/passes/memory/memory_libmap.cc b/passes/memory/memory_libmap.cc index 898e0af85..d77e4be30 100644 --- a/passes/memory/memory_libmap.cc +++ b/passes/memory/memory_libmap.cc @@ -1706,10 +1706,11 @@ void MemMapping::emit_port(const MemConfig &cfg, std::vector &cells, cons if (pdef.wrbe_separate) { cell->setPort(stringf("\\PORT_%s_WR_EN", name), State::S0); cell->setPort(stringf("\\PORT_%s_WR_BE", name), hw_wren); - cell->setParam(stringf("\\PORT_%s_WR_BE_WIDTH", name), GetSize(hw_wren)); + if (cfg.def->width_mode != WidthMode::Single) + cell->setParam(stringf("\\PORT_%s_WR_BE_WIDTH", name), GetSize(hw_wren)); } else { cell->setPort(stringf("\\PORT_%s_WR_EN", name), hw_wren); - if (cfg.def->byte != 0) + if (cfg.def->byte != 0 && cfg.def->width_mode != WidthMode::Single) cell->setParam(stringf("\\PORT_%s_WR_EN_WIDTH", name), GetSize(hw_wren)); } } -- cgit v1.2.3 From d69091806ad29c3720e478d965354f44bd266d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 17 Jun 2022 01:20:33 +0200 Subject: memory_libmap: Fix wrprio handling. --- passes/memory/memory_libmap.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/memory/memory_libmap.cc b/passes/memory/memory_libmap.cc index d77e4be30..9e147b0bf 100644 --- a/passes/memory/memory_libmap.cc +++ b/passes/memory/memory_libmap.cc @@ -837,7 +837,7 @@ void MemMapping::handle_priority() { if (!port2.priority_mask[p1idx]) continue; for (auto &cfg: cfgs) { - auto &p1cfg = cfg.rd_ports[p1idx]; + auto &p1cfg = cfg.wr_ports[p1idx]; auto &p2cfg = cfg.wr_ports[p2idx]; bool found = false; for (auto &pgi: p2cfg.def->wrprio) { -- cgit v1.2.3 From bb634d39ef6c2b915a7b7526029197ecf948e183 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 17 Jun 2022 00:17:38 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f85ea0b53..41d4dbfad 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.18+10 +YOSYS_VER := 0.18+13 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From 01daa077a2837830914f3d99f351918d690b9093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 17 Jun 2022 14:11:04 +0200 Subject: memory_map: Use const drivers instead of FFs for ROMs. --- passes/memory/memory_map.cc | 111 +++++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 52 deletions(-) diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index ca1ca483d..21c7a761e 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -191,6 +191,10 @@ struct MemoryMapWorker data_reg_out[idx] = static_cells_map[addr]; count_static++; } + else if (mem.wr_ports.empty()) + { + data_reg_out[idx] = init_data.extract(i*mem.width, mem.width); + } else { RTLIL::Cell *c = module->addCell(genid(mem.memid, "", addr), ID($dff)); @@ -266,69 +270,72 @@ struct MemoryMapWorker log(" read interface: %d $dff and %d $mux cells.\n", count_dff, count_mux); - for (int i = 0; i < mem.size; i++) + if (!mem.wr_ports.empty()) { - int addr = i + mem.start_offset; - int idx = addr & ((1 << abits) - 1); - if (static_cells_map.count(addr) > 0) - continue; - - RTLIL::SigSpec sig = data_reg_out[idx]; - - for (int j = 0; j < GetSize(mem.wr_ports); j++) + for (int i = 0; i < mem.size; i++) { - auto &port = mem.wr_ports[j]; - RTLIL::SigSpec wr_addr = port.addr.extract_end(port.wide_log2); - RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(addr >> port.wide_log2, GetSize(wr_addr))); + int addr = i + mem.start_offset; + int idx = addr & ((1 << abits) - 1); + if (static_cells_map.count(addr) > 0) + continue; - int sub = addr & ((1 << port.wide_log2) - 1); + RTLIL::SigSpec sig = data_reg_out[idx]; - int wr_offset = 0; - while (wr_offset < mem.width) + for (int j = 0; j < GetSize(mem.wr_ports); j++) { - int wr_width = 1; - RTLIL::SigSpec wr_bit = port.en.extract(wr_offset + sub * mem.width, 1); - - while (wr_offset + wr_width < mem.width) { - RTLIL::SigSpec next_wr_bit = port.en.extract(wr_offset + wr_width + sub * mem.width, 1); - if (next_wr_bit != wr_bit) - break; - wr_width++; - } + auto &port = mem.wr_ports[j]; + RTLIL::SigSpec wr_addr = port.addr.extract_end(port.wide_log2); + RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(addr >> port.wide_log2, GetSize(wr_addr))); - RTLIL::Wire *w = w_seladdr; + int sub = addr & ((1 << port.wide_log2) - 1); - if (wr_bit != State::S1) + int wr_offset = 0; + while (wr_offset < mem.width) { - RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wren", addr, "", j, "", wr_offset), ID($and)); - c->parameters[ID::A_SIGNED] = RTLIL::Const(0); - c->parameters[ID::B_SIGNED] = RTLIL::Const(0); - c->parameters[ID::A_WIDTH] = RTLIL::Const(1); - c->parameters[ID::B_WIDTH] = RTLIL::Const(1); - c->parameters[ID::Y_WIDTH] = RTLIL::Const(1); - c->setPort(ID::A, w); - c->setPort(ID::B, wr_bit); - - w = module->addWire(genid(mem.memid, "$wren", addr, "", j, "", wr_offset, "$y")); - c->setPort(ID::Y, RTLIL::SigSpec(w)); + int wr_width = 1; + RTLIL::SigSpec wr_bit = port.en.extract(wr_offset + sub * mem.width, 1); + + while (wr_offset + wr_width < mem.width) { + RTLIL::SigSpec next_wr_bit = port.en.extract(wr_offset + wr_width + sub * mem.width, 1); + if (next_wr_bit != wr_bit) + break; + wr_width++; + } + + RTLIL::Wire *w = w_seladdr; + + if (wr_bit != State::S1) + { + RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wren", addr, "", j, "", wr_offset), ID($and)); + c->parameters[ID::A_SIGNED] = RTLIL::Const(0); + c->parameters[ID::B_SIGNED] = RTLIL::Const(0); + c->parameters[ID::A_WIDTH] = RTLIL::Const(1); + c->parameters[ID::B_WIDTH] = RTLIL::Const(1); + c->parameters[ID::Y_WIDTH] = RTLIL::Const(1); + c->setPort(ID::A, w); + c->setPort(ID::B, wr_bit); + + w = module->addWire(genid(mem.memid, "$wren", addr, "", j, "", wr_offset, "$y")); + c->setPort(ID::Y, RTLIL::SigSpec(w)); + } + + RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset), ID($mux)); + c->parameters[ID::WIDTH] = wr_width; + c->setPort(ID::A, sig.extract(wr_offset, wr_width)); + c->setPort(ID::B, port.data.extract(wr_offset + sub * mem.width, wr_width)); + c->setPort(ID::S, RTLIL::SigSpec(w)); + + w = module->addWire(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset, "$y"), wr_width); + c->setPort(ID::Y, w); + + sig.replace(wr_offset, w); + wr_offset += wr_width; + count_wrmux++; } - - RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset), ID($mux)); - c->parameters[ID::WIDTH] = wr_width; - c->setPort(ID::A, sig.extract(wr_offset, wr_width)); - c->setPort(ID::B, port.data.extract(wr_offset + sub * mem.width, wr_width)); - c->setPort(ID::S, RTLIL::SigSpec(w)); - - w = module->addWire(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset, "$y"), wr_width); - c->setPort(ID::Y, w); - - sig.replace(wr_offset, w); - wr_offset += wr_width; - count_wrmux++; } - } - module->connect(RTLIL::SigSig(data_reg_in[idx], sig)); + module->connect(RTLIL::SigSig(data_reg_in[idx], sig)); + } } log(" write interface: %d write mux blocks.\n", count_wrmux); -- cgit v1.2.3 From 607e957657fc56625de5c28ea9cd43c859017d96 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 17 Jun 2022 16:04:22 +0200 Subject: use new verific extensions library --- frontends/verific/verific.cc | 124 ++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 54 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index bbf860c96..5e610c0f3 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -58,6 +58,9 @@ USING_YOSYS_NAMESPACE #ifdef YOSYSHQ_VERIFIC_EXTENSIONS #include "InitialAssertions.h" +#include "VerificBasePass.h" +#include "TemplateGenerator.h" +#include "FormalApplication.h" #endif #ifndef YOSYSHQ_VERIFIC_API_VERSION @@ -149,6 +152,8 @@ public: } }; +static YosysStreamCallBackHandler stream_cb; + // ================================================================== VerificImporter::VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover, bool mode_fullinit) : @@ -2345,6 +2350,64 @@ bool check_noverific_env() return false; return true; } + +void set_verific_global_flags() +{ + static bool g_set_verific_global_flags = true; + + if (g_set_verific_global_flags) + { + Message::SetConsoleOutput(0); + Message::RegisterCallBackMsg(msg_func); + + RuntimeFlags::SetVar("db_preserve_user_instances", 1); + RuntimeFlags::SetVar("db_preserve_user_nets", 1); + RuntimeFlags::SetVar("db_preserve_x", 1); + + RuntimeFlags::SetVar("db_allow_external_nets", 1); + RuntimeFlags::SetVar("db_infer_wide_operators", 1); + RuntimeFlags::SetVar("db_infer_set_reset_registers", 0); + + RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); + RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); + RuntimeFlags::SetVar("veri_allow_any_ram_in_loop", 1); + +#ifdef VERIFIC_VHDL_SUPPORT + RuntimeFlags::SetVar("vhdl_extract_dualport_rams", 0); + RuntimeFlags::SetVar("vhdl_extract_multiport_rams", 1); + RuntimeFlags::SetVar("vhdl_allow_any_ram_in_loop", 1); + + RuntimeFlags::SetVar("vhdl_support_variable_slice", 1); + RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0); + + RuntimeFlags::SetVar("vhdl_preserve_assignments", 1); + //RuntimeFlags::SetVar("vhdl_preserve_comments", 1); + RuntimeFlags::SetVar("vhdl_preserve_drivers", 1); +#endif + RuntimeFlags::SetVar("veri_preserve_assignments", 1); + RuntimeFlags::SetVar("veri_preserve_comments", 1); + RuntimeFlags::SetVar("veri_preserve_drivers", 1); + + // Workaround for VIPER #13851 + RuntimeFlags::SetVar("veri_create_name_for_unnamed_gen_block", 1); + + // WARNING: instantiating unknown module 'XYZ' (VERI-1063) + Message::SetMessageType("VERI-1063", VERIFIC_ERROR); + + // https://github.com/YosysHQ/yosys/issues/1055 + RuntimeFlags::SetVar("veri_elaborate_top_level_modules_having_interface_ports", 1) ; + + RuntimeFlags::SetVar("verific_produce_verbose_syntax_error_message", 1); + +#ifndef DB_PRESERVE_INITIAL_VALUE +# warning Verific was built without DB_PRESERVE_INITIAL_VALUE. +#endif + + veri_file::RegisterCallBackVerificStream(&stream_cb); + + g_set_verific_global_flags = false; + } +} #endif struct VerificPass : public Pass { @@ -2549,8 +2612,6 @@ struct VerificPass : public Pass { #ifdef YOSYS_ENABLE_VERIFIC void execute(std::vector args, RTLIL::Design *design) override { - static bool set_verific_global_flags = true; - if (check_noverific_env()) log_cmd_error("This version of Yosys is built without Verific support.\n" "\n" @@ -2562,56 +2623,7 @@ struct VerificPass : public Pass { log_header(design, "Executing VERIFIC (loading SystemVerilog and VHDL designs using Verific).\n"); - if (set_verific_global_flags) - { - Message::SetConsoleOutput(0); - Message::RegisterCallBackMsg(msg_func); - - RuntimeFlags::SetVar("db_preserve_user_instances", 1); - RuntimeFlags::SetVar("db_preserve_user_nets", 1); - RuntimeFlags::SetVar("db_preserve_x", 1); - - RuntimeFlags::SetVar("db_allow_external_nets", 1); - RuntimeFlags::SetVar("db_infer_wide_operators", 1); - RuntimeFlags::SetVar("db_infer_set_reset_registers", 0); - - RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); - RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); - RuntimeFlags::SetVar("veri_allow_any_ram_in_loop", 1); - -#ifdef VERIFIC_VHDL_SUPPORT - RuntimeFlags::SetVar("vhdl_extract_dualport_rams", 0); - RuntimeFlags::SetVar("vhdl_extract_multiport_rams", 1); - RuntimeFlags::SetVar("vhdl_allow_any_ram_in_loop", 1); - - RuntimeFlags::SetVar("vhdl_support_variable_slice", 1); - RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0); - - RuntimeFlags::SetVar("vhdl_preserve_assignments", 1); - //RuntimeFlags::SetVar("vhdl_preserve_comments", 1); - RuntimeFlags::SetVar("vhdl_preserve_drivers", 1); -#endif - RuntimeFlags::SetVar("veri_preserve_assignments", 1); - RuntimeFlags::SetVar("veri_preserve_comments", 1); - RuntimeFlags::SetVar("veri_preserve_drivers", 1); - - // Workaround for VIPER #13851 - RuntimeFlags::SetVar("veri_create_name_for_unnamed_gen_block", 1); - - // WARNING: instantiating unknown module 'XYZ' (VERI-1063) - Message::SetMessageType("VERI-1063", VERIFIC_ERROR); - - // https://github.com/YosysHQ/yosys/issues/1055 - RuntimeFlags::SetVar("veri_elaborate_top_level_modules_having_interface_ports", 1) ; - - RuntimeFlags::SetVar("verific_produce_verbose_syntax_error_message", 1); - -#ifndef DB_PRESERVE_INITIAL_VALUE -# warning Verific was built without DB_PRESERVE_INITIAL_VALUE. -#endif - - set_verific_global_flags = false; - } + set_verific_global_flags(); verific_verbose = 0; verific_sva_fsm_limit = 16; @@ -2630,8 +2642,6 @@ struct VerificPass : public Pass { int argidx = 1; std::string work = "work"; - YosysStreamCallBackHandler cb; - veri_file::RegisterCallBackVerificStream(&cb); if (GetSize(args) > argidx && (args[argidx] == "-set-error" || args[argidx] == "-set-warning" || args[argidx] == "-set-info" || args[argidx] == "-set-ignore")) @@ -3208,6 +3218,12 @@ struct VerificPass : public Pass { #endif } VerificPass; + +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS +VERIFIC_PASS(VerificTemplateGenerator, "template", "generate template") +VERIFIC_PASS(VerificFormalApplication, "formal_app", "running formal application") +#endif + struct ReadPass : public Pass { ReadPass() : Pass("read", "load HDL designs") { } void help() override -- cgit v1.2.3 From ab3a9325c33b5b1b9de6971b6931ee12c3e3871c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 17 Jun 2022 15:29:37 +0200 Subject: memory_map: Add -rom-only option. --- passes/memory/memory_map.cc | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index 21c7a761e..ccfb8c94f 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -30,6 +30,7 @@ PRIVATE_NAMESPACE_BEGIN struct MemoryMapWorker { bool attr_icase = false; + bool rom_only = false; dict> attributes; RTLIL::Design *design; @@ -107,11 +108,8 @@ struct MemoryMapWorker SigSpec init_data = mem.get_init_data(); - // delete unused memory cell - if (mem.rd_ports.empty()) { - mem.remove(); + if (!mem.wr_ports.empty() && rom_only) return; - } // check if attributes allow us to infer FFRAM for this memory for (const auto &attr : attributes) { @@ -143,6 +141,12 @@ struct MemoryMapWorker } } + // delete unused memory cell + if (mem.rd_ports.empty()) { + mem.remove(); + return; + } + // all write ports must share the same clock RTLIL::SigSpec refclock; bool refclock_pol = false; @@ -373,10 +377,14 @@ struct MemoryMapPass : public Pass { log(" -iattr\n"); log(" for -attr, ignore case of .\n"); log("\n"); + log(" -rom-only\n"); + log(" only perform conversion for ROMs (memories with no write ports).\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { bool attr_icase = false; + bool rom_only = false; dict> attributes; log_header(design, "Executing MEMORY_MAP pass (converting memories to logic and flip-flops).\n"); @@ -413,6 +421,11 @@ struct MemoryMapPass : public Pass { attr_icase = true; continue; } + if (args[argidx] == "-rom-only") + { + rom_only = true; + continue; + } break; } extra_args(args, argidx, design); @@ -421,6 +434,7 @@ struct MemoryMapPass : public Pass { MemoryMapWorker worker(design, mod); worker.attr_icase = attr_icase; worker.attributes = attributes; + worker.rom_only = rom_only; worker.run(); } } -- cgit v1.2.3 From 4adef63cd484d81da08ae6b5fe49b1d5d4d0b369 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Fri, 17 Jun 2022 17:23:13 +0200 Subject: smt2, btor: Use memory_map -rom-only to make ROMs usable for k-induction This avoids provability regressions now that we infer more ROMs. This fixes #3378 --- backends/btor/btor.cc | 1 + backends/smt2/smt2.cc | 1 + 2 files changed, 2 insertions(+) diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index 7de5deadd..5be9bf324 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -1402,6 +1402,7 @@ struct BtorBackend : public Backend { log_header(design, "Executing BTOR backend.\n"); log_push(); + Pass::call(design, "memory_map -rom-only"); Pass::call(design, "bmuxmap"); Pass::call(design, "demuxmap"); log_pop(); diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index 7481e0510..6e70f9043 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -1609,6 +1609,7 @@ struct Smt2Backend : public Backend { log_header(design, "Executing SMT2 backend.\n"); log_push(); + Pass::call(design, "memory_map -rom-only"); Pass::call(design, "bmuxmap"); Pass::call(design, "demuxmap"); log_pop(); -- cgit v1.2.3 From 90147f5fbf38aef79067dfb92a9e5eceff791ba7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 18 Jun 2022 00:17:32 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 41d4dbfad..cfdf2c2e0 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.18+13 +YOSYS_VER := 0.18+20 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From 34804f3fb63d8f576ec614904171c1384839cd73 Mon Sep 17 00:00:00 2001 From: Lofty Date: Mon, 20 Jun 2022 15:01:52 +0100 Subject: codeowners: adopt ABC9 and update intel_alm username --- CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 11a8cc026..a33a9a68c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -16,7 +16,7 @@ backends/cxxrtl/ @whitequark passes/cmds/bugpoint.cc @whitequark passes/techmap/flowmap.cc @whitequark passes/opt/opt_lut.cc @whitequark -passes/techmap/abc9*.cc @eddiehung +passes/techmap/abc9*.cc @eddiehung @Ravenslofty backends/aiger/xaiger.cc @eddiehung @@ -30,7 +30,7 @@ backends/aiger/xaiger.cc @eddiehung frontends/verilog/ @zachjs frontends/ast/ @zachjs -techlibs/intel_alm/ @ZirconiumX +techlibs/intel_alm/ @Ravenslofty techlibs/gowin/ @pepijndevos techlibs/gatemate/ @pu-cc -- cgit v1.2.3 From de5c4bf52320e1c19d79a13fcbe303f590d531c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20L=C3=A4ufer?= Date: Mon, 20 Jun 2022 16:39:53 -0700 Subject: btor: add support for $pos cell --- backends/btor/btor.cc | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index 5be9bf324..7dec70545 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -446,25 +446,28 @@ struct BtorWorker goto okay; } - if (cell->type.in(ID($not), ID($neg), ID($_NOT_))) + if (cell->type.in(ID($not), ID($neg), ID($_NOT_), ID($pos))) { string btor_op; if (cell->type.in(ID($not), ID($_NOT_))) btor_op = "not"; if (cell->type == ID($neg)) btor_op = "neg"; - log_assert(!btor_op.empty()); int width = std::max(GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::Y))); bool a_signed = cell->hasParam(ID::A_SIGNED) ? cell->getParam(ID::A_SIGNED).as_bool() : false; - - int sid = get_bv_sid(width); int nid_a = get_sig_nid(cell->getPort(ID::A), width, a_signed); - - int nid = next_nid++; - btorf("%d %s %d %d%s\n", nid, btor_op.c_str(), sid, nid_a, getinfo(cell).c_str()); - SigSpec sig = sigmap(cell->getPort(ID::Y)); + // the $pos cell just passes through, all other cells need an actual operation applied + int nid = nid_a; + if (cell->type != ID($pos)) + { + log_assert(!btor_op.empty()); + int sid = get_bv_sid(width); + nid = next_nid++; + btorf("%d %s %d %d%s\n", nid, btor_op.c_str(), sid, nid_a, getinfo(cell).c_str()); + } + if (GetSize(sig) < width) { int sid = get_bv_sid(GetSize(sig)); int nid2 = next_nid++; -- cgit v1.2.3 From 0b486c56e844f7645a34f58717e89b589cc276d3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 21 Jun 2022 00:16:10 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index cfdf2c2e0..4f43b0b5d 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.18+20 +YOSYS_VER := 0.18+22 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From 1fdbb42fdd51aa940e4331cdf5b4d1ff56738658 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 21 Jun 2022 18:06:16 +0200 Subject: Revert "use new verific extensions library" This reverts commit 607e957657fc56625de5c28ea9cd43c859017d96. --- frontends/verific/verific.cc | 124 +++++++++++++++++++------------------------ 1 file changed, 54 insertions(+), 70 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 5e610c0f3..bbf860c96 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -58,9 +58,6 @@ USING_YOSYS_NAMESPACE #ifdef YOSYSHQ_VERIFIC_EXTENSIONS #include "InitialAssertions.h" -#include "VerificBasePass.h" -#include "TemplateGenerator.h" -#include "FormalApplication.h" #endif #ifndef YOSYSHQ_VERIFIC_API_VERSION @@ -152,8 +149,6 @@ public: } }; -static YosysStreamCallBackHandler stream_cb; - // ================================================================== VerificImporter::VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover, bool mode_fullinit) : @@ -2350,64 +2345,6 @@ bool check_noverific_env() return false; return true; } - -void set_verific_global_flags() -{ - static bool g_set_verific_global_flags = true; - - if (g_set_verific_global_flags) - { - Message::SetConsoleOutput(0); - Message::RegisterCallBackMsg(msg_func); - - RuntimeFlags::SetVar("db_preserve_user_instances", 1); - RuntimeFlags::SetVar("db_preserve_user_nets", 1); - RuntimeFlags::SetVar("db_preserve_x", 1); - - RuntimeFlags::SetVar("db_allow_external_nets", 1); - RuntimeFlags::SetVar("db_infer_wide_operators", 1); - RuntimeFlags::SetVar("db_infer_set_reset_registers", 0); - - RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); - RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); - RuntimeFlags::SetVar("veri_allow_any_ram_in_loop", 1); - -#ifdef VERIFIC_VHDL_SUPPORT - RuntimeFlags::SetVar("vhdl_extract_dualport_rams", 0); - RuntimeFlags::SetVar("vhdl_extract_multiport_rams", 1); - RuntimeFlags::SetVar("vhdl_allow_any_ram_in_loop", 1); - - RuntimeFlags::SetVar("vhdl_support_variable_slice", 1); - RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0); - - RuntimeFlags::SetVar("vhdl_preserve_assignments", 1); - //RuntimeFlags::SetVar("vhdl_preserve_comments", 1); - RuntimeFlags::SetVar("vhdl_preserve_drivers", 1); -#endif - RuntimeFlags::SetVar("veri_preserve_assignments", 1); - RuntimeFlags::SetVar("veri_preserve_comments", 1); - RuntimeFlags::SetVar("veri_preserve_drivers", 1); - - // Workaround for VIPER #13851 - RuntimeFlags::SetVar("veri_create_name_for_unnamed_gen_block", 1); - - // WARNING: instantiating unknown module 'XYZ' (VERI-1063) - Message::SetMessageType("VERI-1063", VERIFIC_ERROR); - - // https://github.com/YosysHQ/yosys/issues/1055 - RuntimeFlags::SetVar("veri_elaborate_top_level_modules_having_interface_ports", 1) ; - - RuntimeFlags::SetVar("verific_produce_verbose_syntax_error_message", 1); - -#ifndef DB_PRESERVE_INITIAL_VALUE -# warning Verific was built without DB_PRESERVE_INITIAL_VALUE. -#endif - - veri_file::RegisterCallBackVerificStream(&stream_cb); - - g_set_verific_global_flags = false; - } -} #endif struct VerificPass : public Pass { @@ -2612,6 +2549,8 @@ struct VerificPass : public Pass { #ifdef YOSYS_ENABLE_VERIFIC void execute(std::vector args, RTLIL::Design *design) override { + static bool set_verific_global_flags = true; + if (check_noverific_env()) log_cmd_error("This version of Yosys is built without Verific support.\n" "\n" @@ -2623,7 +2562,56 @@ struct VerificPass : public Pass { log_header(design, "Executing VERIFIC (loading SystemVerilog and VHDL designs using Verific).\n"); - set_verific_global_flags(); + if (set_verific_global_flags) + { + Message::SetConsoleOutput(0); + Message::RegisterCallBackMsg(msg_func); + + RuntimeFlags::SetVar("db_preserve_user_instances", 1); + RuntimeFlags::SetVar("db_preserve_user_nets", 1); + RuntimeFlags::SetVar("db_preserve_x", 1); + + RuntimeFlags::SetVar("db_allow_external_nets", 1); + RuntimeFlags::SetVar("db_infer_wide_operators", 1); + RuntimeFlags::SetVar("db_infer_set_reset_registers", 0); + + RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); + RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); + RuntimeFlags::SetVar("veri_allow_any_ram_in_loop", 1); + +#ifdef VERIFIC_VHDL_SUPPORT + RuntimeFlags::SetVar("vhdl_extract_dualport_rams", 0); + RuntimeFlags::SetVar("vhdl_extract_multiport_rams", 1); + RuntimeFlags::SetVar("vhdl_allow_any_ram_in_loop", 1); + + RuntimeFlags::SetVar("vhdl_support_variable_slice", 1); + RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0); + + RuntimeFlags::SetVar("vhdl_preserve_assignments", 1); + //RuntimeFlags::SetVar("vhdl_preserve_comments", 1); + RuntimeFlags::SetVar("vhdl_preserve_drivers", 1); +#endif + RuntimeFlags::SetVar("veri_preserve_assignments", 1); + RuntimeFlags::SetVar("veri_preserve_comments", 1); + RuntimeFlags::SetVar("veri_preserve_drivers", 1); + + // Workaround for VIPER #13851 + RuntimeFlags::SetVar("veri_create_name_for_unnamed_gen_block", 1); + + // WARNING: instantiating unknown module 'XYZ' (VERI-1063) + Message::SetMessageType("VERI-1063", VERIFIC_ERROR); + + // https://github.com/YosysHQ/yosys/issues/1055 + RuntimeFlags::SetVar("veri_elaborate_top_level_modules_having_interface_ports", 1) ; + + RuntimeFlags::SetVar("verific_produce_verbose_syntax_error_message", 1); + +#ifndef DB_PRESERVE_INITIAL_VALUE +# warning Verific was built without DB_PRESERVE_INITIAL_VALUE. +#endif + + set_verific_global_flags = false; + } verific_verbose = 0; verific_sva_fsm_limit = 16; @@ -2642,6 +2630,8 @@ struct VerificPass : public Pass { int argidx = 1; std::string work = "work"; + YosysStreamCallBackHandler cb; + veri_file::RegisterCallBackVerificStream(&cb); if (GetSize(args) > argidx && (args[argidx] == "-set-error" || args[argidx] == "-set-warning" || args[argidx] == "-set-info" || args[argidx] == "-set-ignore")) @@ -3218,12 +3208,6 @@ struct VerificPass : public Pass { #endif } VerificPass; - -#ifdef YOSYSHQ_VERIFIC_EXTENSIONS -VERIFIC_PASS(VerificTemplateGenerator, "template", "generate template") -VERIFIC_PASS(VerificFormalApplication, "formal_app", "running formal application") -#endif - struct ReadPass : public Pass { ReadPass() : Pass("read", "load HDL designs") { } void help() override -- cgit v1.2.3 From 7eeb656e2a8276f71c7b7ba7031618c5b7b0849a Mon Sep 17 00:00:00 2001 From: Archie Date: Tue, 14 Jun 2022 14:17:00 +0100 Subject: Add check for BLIF with no model name --- frontends/blif/blifparse.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc index 19844bda6..73d1f0ea7 100644 --- a/frontends/blif/blifparse.cc +++ b/frontends/blif/blifparse.cc @@ -166,7 +166,10 @@ void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool goto error; module = new RTLIL::Module; lastcell = nullptr; - module->name = RTLIL::escape_id(strtok(NULL, " \t\r\n")); + char *name = strtok(NULL, " \t\r\n"); + if (name == nullptr) + goto error; + module->name = RTLIL::escape_id(name); obj_attributes = &module->attributes; obj_parameters = nullptr; if (design->module(module->name)) -- cgit v1.2.3 From c8cd4f468a30f8b29160d5ba62ae08d644341263 Mon Sep 17 00:00:00 2001 From: Archie Date: Fri, 17 Jun 2022 20:07:02 +0100 Subject: Adding testcase for issue 3374 --- tests/blif/bug3374.ys | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/blif/bug3374.ys diff --git a/tests/blif/bug3374.ys b/tests/blif/bug3374.ys new file mode 100644 index 000000000..d7d8c765b --- /dev/null +++ b/tests/blif/bug3374.ys @@ -0,0 +1,3 @@ +read_blif < Date: Mon, 20 Jun 2022 21:50:26 +0100 Subject: Adding expected error message. --- tests/blif/bug3374.ys | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/blif/bug3374.ys b/tests/blif/bug3374.ys index d7d8c765b..792d4de20 100644 --- a/tests/blif/bug3374.ys +++ b/tests/blif/bug3374.ys @@ -1,3 +1,4 @@ +logger -expect error "Syntax error in line 1!" 1 read_blif < Date: Wed, 22 Jun 2022 00:19:30 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4f43b0b5d..3c659b9aa 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.18+22 +YOSYS_VER := 0.18+29 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From c16c0288311ba9aef95b3d5fcdde63bbc05a5b08 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Wed, 22 Jun 2022 20:53:10 -0700 Subject: add hierarchy -smtcheck like -simcheck, but allow smtlib2_module modules. --- manual/command-reference-manual.tex | 3 +++ passes/hierarchy/hierarchy.cc | 23 ++++++++++++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/manual/command-reference-manual.tex b/manual/command-reference-manual.tex index edc8af6e6..3a9259867 100644 --- a/manual/command-reference-manual.tex +++ b/manual/command-reference-manual.tex @@ -2379,6 +2379,9 @@ resolves positional module parameters, unrolls array instances, and more. like -check, but also throw an error if blackbox modules are instantiated, and throw an error if the design has no top module. + -smtcheck + like -simcheck, but allow smtlib2_module modules. + -purge_lib by default the hierarchy command will not remove library (blackbox) modules. use this option to also remove unused blackbox modules. diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index d40d6e59f..d27fddf1c 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -439,7 +439,8 @@ void check_cell_connections(const RTLIL::Module &module, RTLIL::Cell &cell, RTLI } } -bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, std::vector &libdirs) +bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, bool flag_smtcheck, + std::vector &libdirs) { bool did_something = false; std::map> array_cells; @@ -477,7 +478,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check RTLIL::Module *mod = design->module(cell->type); if (!mod) { - mod = get_module(*design, *cell, *module, flag_check || flag_simcheck, libdirs); + mod = get_module(*design, *cell, *module, flag_check || flag_simcheck || flag_smtcheck, libdirs); // If we still don't have a module, treat the cell as a black box and skip // it. Otherwise, we either loaded or derived something so should set the @@ -495,11 +496,11 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check // interfaces. if_expander.visit_connections(*cell, *mod); - if (flag_check || flag_simcheck) + if (flag_check || flag_simcheck || flag_smtcheck) check_cell_connections(*module, *cell, *mod); if (mod->get_blackbox_attribute()) { - if (flag_simcheck) + if (flag_simcheck || (flag_smtcheck && !mod->get_bool_attribute(ID::smtlib2_module))) log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox/whitebox module.\n", cell->type.c_str(), module->name.c_str(), cell->name.c_str()); continue; @@ -737,6 +738,9 @@ struct HierarchyPass : public Pass { log(" like -check, but also throw an error if blackbox modules are\n"); log(" instantiated, and throw an error if the design has no top module.\n"); log("\n"); + log(" -smtcheck\n"); + log(" like -simcheck, but allow smtlib2_module modules.\n"); + log("\n"); log(" -purge_lib\n"); log(" by default the hierarchy command will not remove library (blackbox)\n"); log(" modules. use this option to also remove unused blackbox modules.\n"); @@ -803,6 +807,7 @@ struct HierarchyPass : public Pass { bool flag_check = false; bool flag_simcheck = false; + bool flag_smtcheck = false; bool purge_lib = false; RTLIL::Module *top_mod = NULL; std::string load_top_mod; @@ -821,7 +826,7 @@ struct HierarchyPass : public Pass { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-generate" && !flag_check && !flag_simcheck && !top_mod) { + if (args[argidx] == "-generate" && !flag_check && !flag_simcheck && !flag_smtcheck && !top_mod) { generate_mode = true; log("Entering generate mode.\n"); while (++argidx < args.size()) { @@ -868,6 +873,10 @@ struct HierarchyPass : public Pass { flag_simcheck = true; continue; } + if (args[argidx] == "-smtcheck") { + flag_smtcheck = true; + continue; + } if (args[argidx] == "-purge_lib") { purge_lib = true; continue; @@ -1013,7 +1022,7 @@ struct HierarchyPass : public Pass { } } - if (flag_simcheck && top_mod == nullptr) + if ((flag_simcheck || flag_smtcheck) && top_mod == nullptr) log_error("Design has no top module.\n"); if (top_mod != NULL) { @@ -1039,7 +1048,7 @@ struct HierarchyPass : public Pass { } for (auto module : used_modules) { - if (expand_module(design, module, flag_check, flag_simcheck, libdirs)) + if (expand_module(design, module, flag_check, flag_simcheck, flag_smtcheck, libdirs)) did_something = true; } -- cgit v1.2.3 From ec2f8796bd7a5180f257a92d7ffb2029571cada6 Mon Sep 17 00:00:00 2001 From: rockybulwinkle Date: Thu, 23 Jun 2022 13:34:08 -0500 Subject: Update tcl doc, yosys does not return data to tcl This pull request is to address YosysHQ/yosys#2980. The documentation, as originally written, does not make it clear that yosys commands, when used within a tcl script, do not return any value to the tcl script. This pull request notes this and offers a workaround via tee as noted in the issue. --- kernel/yosys.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 64d2b4def..521717ce7 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -773,6 +773,12 @@ struct TclPass : public Pass { log("\n"); log("If any arguments are specified, these arguments are provided to the script via\n"); log("the standard $argc and $argv variables.\n"); + log("\n"); + log("Note, tcl will not recieve the output of any yosys command. If the output\n"); + log("of the tcl commands are needed, use the yosys command 'tee' to redirect yosys's\n"); + log("output to a temporary file.\n"); + + log("\n"); } void execute(std::vector args, RTLIL::Design *) override { -- cgit v1.2.3 From 7c756c9959b61160ea62b56c13c58371cb2b401c Mon Sep 17 00:00:00 2001 From: gatecat Date: Mon, 6 Dec 2021 13:39:18 +0000 Subject: gatemate: Add preliminary sim models for LUT tree structures Signed-off-by: gatecat --- techlibs/gatemate/cells_sim.v | 44 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/techlibs/gatemate/cells_sim.v b/techlibs/gatemate/cells_sim.v index 1de3d1c7a..7e88fd7cf 100644 --- a/techlibs/gatemate/cells_sim.v +++ b/techlibs/gatemate/cells_sim.v @@ -1409,3 +1409,47 @@ module CC_BRAM_40K ( end endgenerate endmodule + +// Models of the LUT2 tree primitives +module CC_L2T4( + output O, + input I0, I1, I2, I3 +); + parameter [3:0] INIT_L00 = 4'b0000; + parameter [3:0] INIT_L01 = 4'b0000; + parameter [3:0] INIT_L10 = 4'b0000; + + wire [1:0] l00_s1 = I1 ? INIT_L00[3:2] : INIT_L00[1:0]; + wire l00 = I0 ? l00_s1[1] : l00_s1[0]; + + wire [1:0] l01_s1 = I3 ? INIT_L01[3:2] : INIT_L01[1:0]; + wire l01 = I2 ? l01_s1[1] : l01_s1[0]; + + wire [1:0] l10_s1 = l01 ? INIT_L10[3:2] : INIT_L10[1:0]; + assign O = l00 ? l10_s1[1] : l10_s1[0]; + +endmodule + + +module CC_L2T5( + output O, + input I0, I1, I2, I3, I4 +); + parameter [3:0] INIT_L02 = 4'b0000; + parameter [3:0] INIT_L03 = 4'b0000; + parameter [3:0] INIT_L11 = 4'b0000; + parameter [3:0] INIT_L20 = 4'b0000; + + wire [1:0] l02_s1 = I1 ? INIT_L02[3:2] : INIT_L02[1:0]; + wire l02 = I0 ? l02_s1[1] : l02_s1[0]; + + wire [1:0] l03_s1 = I3 ? INIT_L03[3:2] : INIT_L03[1:0]; + wire l03 = I2 ? l03_s1[1] : l03_s1[0]; + + wire [1:0] l11_s1 = l03 ? INIT_L11[3:2] : INIT_L11[1:0]; + wire l11 = l02 ? l11_s1[1] : l11_s1[0]; + + wire [1:0] l20_s1 = l11 ? INIT_L20[3:2] : INIT_L20[1:0]; + assign O = I4 ? l20_s1[1] : l20_s1[0]; + +endmodule -- cgit v1.2.3 From 38a24ec5cc3ae25d46a306bceb94244fad787a19 Mon Sep 17 00:00:00 2001 From: gatecat Date: Tue, 7 Dec 2021 13:41:39 +0000 Subject: gatemate: Add LUT tree library script Co-authored-by: Claire Xenia Wolf Signed-off-by: gatecat --- techlibs/gatemate/.gitignore | 4 + techlibs/gatemate/Makefile.inc | 16 ++ techlibs/gatemate/gatemate_foldinv.cc | 218 ++++++++++++++++++++++ techlibs/gatemate/inv_map.v | 4 + techlibs/gatemate/make_lut_tree_lib.py | 323 +++++++++++++++++++++++++++++++++ techlibs/gatemate/synth_gatemate.cc | 32 +++- 6 files changed, 591 insertions(+), 6 deletions(-) create mode 100644 techlibs/gatemate/.gitignore create mode 100644 techlibs/gatemate/gatemate_foldinv.cc create mode 100644 techlibs/gatemate/inv_map.v create mode 100644 techlibs/gatemate/make_lut_tree_lib.py diff --git a/techlibs/gatemate/.gitignore b/techlibs/gatemate/.gitignore new file mode 100644 index 000000000..f260d6e9d --- /dev/null +++ b/techlibs/gatemate/.gitignore @@ -0,0 +1,4 @@ +lut_tree_cells.genlib +lut_tree_map.v +lut_tree_lib.mk + diff --git a/techlibs/gatemate/Makefile.inc b/techlibs/gatemate/Makefile.inc index d1341d7bb..aeb318cc9 100644 --- a/techlibs/gatemate/Makefile.inc +++ b/techlibs/gatemate/Makefile.inc @@ -1,5 +1,6 @@ OBJS += techlibs/gatemate/synth_gatemate.o +OBJS += techlibs/gatemate/gatemate_foldinv.o $(eval $(call add_share_file,share/gatemate,techlibs/gatemate/reg_map.v)) $(eval $(call add_share_file,share/gatemate,techlibs/gatemate/mux_map.v)) @@ -12,3 +13,18 @@ $(eval $(call add_share_file,share/gatemate,techlibs/gatemate/brams_map.v)) $(eval $(call add_share_file,share/gatemate,techlibs/gatemate/brams.txt)) $(eval $(call add_share_file,share/gatemate,techlibs/gatemate/brams_init_20.vh)) $(eval $(call add_share_file,share/gatemate,techlibs/gatemate/brams_init_40.vh)) +$(eval $(call add_share_file,share/gatemate,techlibs/gatemate/inv_map.v)) + +EXTRA_OBJS += techlibs/gatemate/lut_tree_lib.mk +.SECONDARY: techlibs/gatemate/lut_tree_lib.mk + +techlibs/gatemate/lut_tree_lib.mk: techlibs/gatemate/make_lut_tree_lib.py + $(Q) mkdir -p techlibs/gatemate + $(P) $(PYTHON_EXECUTABLE) $< + $(Q) touch $@ + +techlibs/gatemate/lut_tree_cells.genlib: techlibs/gatemate/lut_tree_lib.mk +techlibs/gatemate/lut_tree_map.v: techlibs/gatemate/lut_tree_lib.mk + +$(eval $(call add_gen_share_file,share/gatemate,techlibs/gatemate/lut_tree_cells.genlib)) +$(eval $(call add_gen_share_file,share/gatemate,techlibs/gatemate/lut_tree_map.v)) diff --git a/techlibs/gatemate/gatemate_foldinv.cc b/techlibs/gatemate/gatemate_foldinv.cc new file mode 100644 index 000000000..20fbbf8a3 --- /dev/null +++ b/techlibs/gatemate/gatemate_foldinv.cc @@ -0,0 +1,218 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2021 gatecat + * Copyright (C) 2021 Cologne Chip AG + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct LUTPin { + int input_bit; + IdString init_param; +}; + +struct LUTType { + dict inputs; + IdString output_param; +}; + +static const dict lut_types = { + {ID(CC_LUT2), {{ + {ID(I0), {0, ID(INIT)}}, + {ID(I1), {1, ID(INIT)}}, + }, ID(INIT)}}, + {ID(CC_L2T4), {{ + {ID(I0), {0, ID(INIT_L00)}}, + {ID(I1), {1, ID(INIT_L00)}}, + {ID(I2), {0, ID(INIT_L01)}}, + {ID(I3), {1, ID(INIT_L01)}}, + }, ID(INIT_L10)}}, + {ID(CC_L2T5), {{ + {ID(I0), {0, ID(INIT_L02)}}, + {ID(I1), {1, ID(INIT_L02)}}, + {ID(I2), {0, ID(INIT_L03)}}, + {ID(I3), {1, ID(INIT_L03)}}, + {ID(I4), {0, ID(INIT_L20)}}, + }, ID(INIT_L20)}}, +}; + +struct FoldInvWorker { + FoldInvWorker(Module *module) : module(module), sigmap(module) {}; + Module *module; + SigMap sigmap; + + // Mapping from inverter output to inverter input + dict inverted_bits; + // Mapping from inverter input to inverter + dict inverter_input; + + void find_inverted_bits() + { + for (auto cell : module->selected_cells()) { + if (cell->type != ID($__CC_NOT)) + continue; + SigBit a = sigmap(cell->getPort(ID::A)[0]); + SigBit y = sigmap(cell->getPort(ID::Y)[0]); + inverted_bits[y] = a; + inverter_input[a] = cell; + } + } + + Const invert_lut_input(Const lut, int bit) + { + Const result(State::S0, GetSize(lut)); + for (int i = 0; i < GetSize(lut); i++) { + int j = i ^ (1 << bit); + result[j] = lut[i]; + } + return result; + } + + Const invert_lut_output(Const lut) + { + Const result(State::S0, GetSize(lut)); + for (int i = 0; i < GetSize(lut); i++) + result[i] = (lut[i] == State::S1) ? State::S0 : State::S1; + return result; + } + + void fold_input_inverters() + { + for (auto cell : module->selected_cells()) { + auto found_type = lut_types.find(cell->type); + if (found_type == lut_types.end()) + continue; + const auto &type = found_type->second; + for (const auto &ipin : type.inputs) { + if (!cell->hasPort(ipin.first)) + continue; + auto sig = cell->getPort(ipin.first); + if (GetSize(sig) == 0) + continue; + SigBit bit = sigmap(sig[0]); + auto inv = inverted_bits.find(bit); + if (inv == inverted_bits.end()) + continue; // not the output of an inverter + // Rewire to inverter input + cell->unsetPort(ipin.first); + cell->setPort(ipin.first, inv->second); + // Rewrite init + cell->setParam(ipin.second.init_param, + invert_lut_input(cell->getParam(ipin.second.init_param), ipin.second.input_bit)); + } + } + } + + void fold_output_inverters() + { + pool used_bits; + // Find bits that are actually used + for (auto cell : module->selected_cells()) { + for (auto conn : cell->connections()) { + if (cell->output(conn.first)) + continue; + for (auto bit : sigmap(conn.second)) + used_bits.insert(bit); + } + } + // Find LUTs driving inverters + // (create a vector to avoid iterate-and-modify issues) + std::vector> lut_inv; + for (auto cell : module->selected_cells()) { + auto found_type = lut_types.find(cell->type); + if (found_type == lut_types.end()) + continue; + if (!cell->hasPort(ID::O)) + continue; + auto o_sig = cell->getPort(ID::O); + if (GetSize(o_sig) == 0) + continue; + SigBit o = sigmap(o_sig[0]); + auto found_inv = inverter_input.find(o); + if (found_inv == inverter_input.end()) + continue; // doesn't drive an inverter + lut_inv.emplace_back(cell, found_inv->second); + } + for (auto pair : lut_inv) { + Cell *orig_lut = pair.first; + Cell *inv = pair.second; + // Find the inverter output + SigBit inv_y = sigmap(inv->getPort(ID::Y)[0]); + // Inverter output might not actually be used; if all users were folded into inputs already + if (!used_bits.count(inv_y)) + continue; + // Create a duplicate of the LUT with an inverted output + // (if the uninverted version becomes unused it will be swept away) + Cell *dup_lut = module->addCell(NEW_ID, orig_lut->type); + inv->unsetPort(ID::Y); + dup_lut->setPort(ID::O, inv_y); + for (auto conn : orig_lut->connections()) { + if (conn.first == ID::O) + continue; + dup_lut->setPort(conn.first, conn.second); + } + for (auto param : orig_lut->parameters) { + if (param.first == lut_types.at(orig_lut->type).output_param) + dup_lut->parameters[param.first] = invert_lut_output(param.second); + else + dup_lut->parameters[param.first] = param.second; + } + } + } + + void operator()() + { + find_inverted_bits(); + fold_input_inverters(); + fold_output_inverters(); + } +}; + +struct GatemateFoldInvPass : public Pass { + GatemateFoldInvPass() : Pass("gatemate_foldinv", "fold inverters into Gatemate LUT trees") { } + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" gatemate_foldinv [selection]\n"); + log("\n"); + log("\n"); + log("This pass searches for $__CC_NOT cells and folds them into CC_LUT2, CC_L2T4\n"); + log("and CC_L2T5 cells as created by LUT tree mapping.\n"); + log("\n"); + } + + void execute(std::vector args, RTLIL::Design *design) override + { + log_header(design, "Executing GATEMATE_FOLDINV pass (folding LUT tree inverters).\n"); + + size_t argidx = 1; + extra_args(args, argidx, design); + + for (Module *module : design->selected_modules()) { + FoldInvWorker worker(module); + worker(); + } + } +} GatemateFoldInvPass; + +PRIVATE_NAMESPACE_END + diff --git a/techlibs/gatemate/inv_map.v b/techlibs/gatemate/inv_map.v new file mode 100644 index 000000000..8a5051747 --- /dev/null +++ b/techlibs/gatemate/inv_map.v @@ -0,0 +1,4 @@ +// Any inverters not folded into LUTs are mapped to a LUT of their own +module \$__CC_NOT (input A, output Y); + CC_LUT1 #(.INIT(2'b01)) _TECHMAP_REPLACE_ (.I0(A), .O(Y)); +endmodule diff --git a/techlibs/gatemate/make_lut_tree_lib.py b/techlibs/gatemate/make_lut_tree_lib.py new file mode 100644 index 000000000..25ca88882 --- /dev/null +++ b/techlibs/gatemate/make_lut_tree_lib.py @@ -0,0 +1,323 @@ +#!/usr/bin/env python3 + +class FNode: + def __init__(self, fun, *args): + self.fun = fun + self.args = args + + if len(self.args) == 0: + assert fun not in ("BUF", "NOT", "AND", "OR", "XOR", "MUX") + + if len(self.args) == 1: + assert fun in ("BUF", "NOT") + + if len(self.args) == 2: + assert fun in ("AND", "OR", "XOR") + + if len(self.args) == 3: + assert fun in ("MUX") + + def __str__(self): + if len(self.args) == 0: + return self.fun + if self.fun == "NOT" and len(self.args[0].args) == 0: + return "!" + self.args[0].fun + return self.fun + "(" + ",".join([str(a) for a in self.args]) + ")" + + def as_genlib_term(self): + if len(self.args) == 0: + return self.fun + if self.fun == "NOT": + assert len(self.args[0].args) == 0 + return "!" + self.args[0].fun + if self.fun == "AND": + return "(" + self.args[0].as_genlib_term() + "*" + self.args[1].as_genlib_term() + ")" + if self.fun == "OR": + return "(" + self.args[0].as_genlib_term() + "+" + self.args[1].as_genlib_term() + ")" + assert False + + def mapMux(self): + if self.fun == "MUX": + A, B, C = self.args + return OR(AND(A, NOT(C)), AND(B, C)).mapMux() + return FNode(self.fun, *[a.mapMux() for a in self.args]) + + def mapXor(self): + if self.fun == "XOR": + A, B = self.args + return OR(AND(A, NOT(B)), AND(NOT(A), B)).mapXor() + return FNode(self.fun, *[a.mapXor() for a in self.args]) + + def mapNot(self): + if self.fun == "BUF": + return self.arg1.mapNot() + if self.fun == "NOT": + if self.args[0].fun == "AND": + return OR(NOT(self.args[0].args[0]),NOT(self.args[0].args[1])).mapNot() + if self.args[0].fun == "OR": + return AND(NOT(self.args[0].args[0]),NOT(self.args[0].args[1])).mapNot() + if self.args[0].fun == "NOT": + return self.args[0].args[0].mapNot() + return FNode(self.fun, *[a.mapNot() for a in self.args]) + + def map(self): + n = self + n = n.mapMux() + n = n.mapXor() + n = n.mapNot() + return n + + def isInv(self): + if len(self.args) == 0: + return False + if self.fun == "XOR": + return False + if self.fun == "NOT": + return self.args[0].isNonInv() + for a in self.args: + if not a.isInv(): + return False + return True + + def isNonInv(self): + if len(self.args) == 0: + return True + if self.fun == "XOR": + return False + if self.fun == "NOT": + return self.args[0].isInv() + for a in self.args: + if not a.isNonInv(): + return False + return True + +A = FNode("A") +B = FNode("B") +C = FNode("C") +D = FNode("D") +E = FNode("E") + +def BUF(arg): return FNode("BUF", arg) +def NOT(arg): return FNode("NOT", arg) +def AND(arg1, arg2): return FNode("AND", arg1, arg2) +def OR(arg1, arg2): return FNode( "OR", arg1, arg2) +def XOR(arg1, arg2): return FNode("XOR", arg1, arg2) +def MUX(arg1, arg2, arg3): return FNode("MUX", arg1, arg2, arg3) + +# Genlib Format: +# +# GATE +# +# PIN +# +# +# +# phase: +# INV, NONINV, or UNKNOWN +# +# cell-logic-function: +# = + + +cells = [ + ["$__CC_BUF", 5, A], + ["$__CC_NOT", 0, NOT(A)], + ["$__CC_MUX", 5, MUX(A, B, C)], +] + +base_cells = [ + ["$__CC2_A", AND(A, B)], + ["$__CC2_O", OR(A, B)], + ["$__CC2_X", XOR(A, B)], + + ["$__CC3_AA", AND(AND(A, B), C)], + ["$__CC3_OO", OR( OR(A, B), C)], + ["$__CC3_XX", XOR(XOR(A, B), C)], + ["$__CC3_AO", OR(AND(A, B), C)], + ["$__CC3_OA", AND( OR(A, B), C)], + ["$__CC3_AX", XOR(AND(A, B), C)], + ["$__CC3_XA", AND(XOR(A, B), C)], + +# ["$__CC3_AAA", AND(AND(A,B),AND(A,C))], +# ["$__CC3_AXA", XOR(AND(A,B),AND(A,C))], +# ["$__CC3_XAX", AND(XOR(A,B),XOR(A,C))], +# ["$__CC3_AAX", AND(AND(A,B),XOR(A,C))], +# ["$__CC3_AXX", XOR(AND(A,B),XOR(A,C))], +# ["$__CC3_XXX", XOR(XOR(A,B),XOR(A,C))], +# ["$__CC3_AAO", AND(AND(A,B), OR(A,C))], +# ["$__CC3_AOA", OR(AND(A,B),AND(A,C))], +# ["$__CC3_AOX", OR(AND(A,B),XOR(A,C))], + +# ["$__CC3_AAA_N", AND(AND(A,B),AND(NOT(A),C))], +# ["$__CC3_AXA_N", XOR(AND(A,B),AND(NOT(A),C))], +# ["$__CC3_XAX_N", AND(XOR(A,B),XOR(NOT(A),C))], +# ["$__CC3_AAX_N", AND(AND(A,B),XOR(NOT(A),C))], +# ["$__CC3_AXX_N", XOR(AND(A,B),XOR(NOT(A),C))], +# ["$__CC3_XXX_N", XOR(XOR(A,B),XOR(NOT(A),C))], +# ["$__CC3_AAO_N", AND(AND(A,B), OR(NOT(A),C))], +# ["$__CC3_AOA_N", OR(AND(A,B),AND(NOT(A),C))], +# ["$__CC3_AOX_N", OR(AND(A,B),XOR(NOT(A),C))], + + ["$__CC4_AAA", AND(AND(A,B),AND(C,D))], + ["$__CC4_AXA", XOR(AND(A,B),AND(C,D))], + ["$__CC4_XAX", AND(XOR(A,B),XOR(C,D))], + ["$__CC4_AAX", AND(AND(A,B),XOR(C,D))], + ["$__CC4_AXX", XOR(AND(A,B),XOR(C,D))], + ["$__CC4_XXX", XOR(XOR(A,B),XOR(C,D))], + ["$__CC4_AAO", AND(AND(A,B), OR(C,D))], + ["$__CC4_AOA", OR(AND(A,B),AND(C,D))], + ["$__CC4_AOX", OR(AND(A,B),XOR(C,D))], +] + +for name, expr in base_cells: + cells.append([name, 10, expr]) + + name = (name + .replace("$__CC4_", "$__CC5_") + .replace("$__CC3_", "$__CC4_") + .replace("$__CC2_", "$__CC3_")) + + # Cells such as $__CC4_AA_A are redundant, as $__CC4_AAA is equivalent + if name not in ("$__CC4_AA", "$__CC3_A"): + cells.append([name + "_A", 12, AND(E, expr)]) + if name not in ("$__CC4_OO", "$__CC3_O"): + cells.append([name + "_O", 12, OR(E, expr)]) + if name not in ("$__CC4_XX", "$__CC3_X"): + cells.append([name + "_X", 12, XOR(E, expr)]) + +with open("techlibs/gatemate/lut_tree_cells.genlib", "w") as glf: + def mkGate(name, cost, expr, max_load=9999, block_delay = 10, fanout_delay = 5): + name = name.replace(" ", "") + expr = expr.map() + + phase = "UNKNOWN" + if expr.isInv(): phase = "INV" + if expr.isNonInv(): phase = "NONINV" + + print("", file=glf) + print("GATE %s %d Y=%s;" % (name, cost, expr.as_genlib_term()), file=glf) + print("PIN * %s 1 %d %d %d %d %d" % (phase, max_load, block_delay, fanout_delay, block_delay, fanout_delay), file=glf) + print("GATE $__ZERO 0 Y=CONST0;", file=glf) + print("GATE $__ONE 0 Y=CONST1;", file=glf) + for name, cost, expr in cells: + mkGate(name, cost, expr) + +class LUTTreeNode: + def __init__(self, name, width, inputs=None): + self.name = name + self.width = width + self.inputs = inputs + def is_input(self): + return self.width == 0 + def map(self, expr, params, ports): + if self.is_input(): + # Input to LUT tree + if expr is None: + ports[self.name] = "" # disconnected input + else: + assert(len(expr.args) == 0) + ports[self.name] = expr.fun + return + if expr is None: + # Unused part of tree + params[self.name] = "4'b0000" + for i in self.inputs: + i.map(None, params, ports) + return + elif len(expr.args) == 0: + # Input to the expression; but not LUT tree + # Insert a route through + params[self.name] = "4'b1010" + self.inputs[0].map(expr, params, ports) + for i in self.inputs[1:]: + i.map(None, params, ports) + return + # Map uphill LUTs; uninverting arguments and keeping track of that if needed + arg_inv = [] + for (i, arg) in zip(self.inputs, expr.args): + if arg.fun == "NOT": + i.map(arg.args[0], params, ports) + arg_inv.append(True) + else: + i.map(arg, params, ports) + arg_inv.append(False) + # Determine base init value + assert self.width == 2 + if expr.fun == "AND": + init = 0b1000 + elif expr.fun == "OR": + init = 0b1110 + elif expr.fun == "XOR": + init = 0b0110 + else: + assert False, expr.fun + # Swap bits if init inverted + swapped_init = 0b0000 + for b in range(4): + if ((init >> b) & 0x1) == 0: continue + for i in range(2): + if arg_inv[i]: + b ^= (1 << i) + swapped_init |= (1 << b) + # Set init param + params[self.name] = "4'b{:04b}".format(swapped_init) + +def LUT2(name, i0, i1): return LUTTreeNode(name, 2, [i0, i1]) +def I(name): return LUTTreeNode(name, 0) + +lut_prims = { + "CC_LUT2": LUT2("INIT", I("I0"), I("I1")), + "CC_L2T4": LUT2( + "INIT_L10", + LUT2("INIT_L00", I("I0"), I("I1")), + LUT2("INIT_L01", I("I2"), I("I3")), + ), + "CC_L2T5": LUT2( + "INIT_L20", I("I4"), LUT2("INIT_L11", + LUT2("INIT_L02", I("I0"), I("I1")), + LUT2("INIT_L03", I("I2"), I("I3")), + ) + ) +} + +with open("techlibs/gatemate/lut_tree_map.v", "w") as vf: + # Non-automatic rules + print(""" +module \\$__ZERO (output Y); assign Y = 1'b0; endmodule +module \\$__ONE (output Y); assign Y = 1'b1; endmodule + +module \\$__CC_BUF (input A, output Y); assign Y = A; endmodule + +module \\$__CC_MUX (input A, B, C, output Y); + CC_MX2 _TECHMAP_REPLACE_ ( + .D0(A), .D1(B), .S0(C), + .Y(Y) + ); +endmodule +""", file=vf) + for name, cost, expr in cells: + expr = expr.mapMux().mapNot() # Don't map XOR + if name in ("$__CC_BUF", "$__CC_NOT", "$__CC_MUX"): + # Special cases + continue + if name.startswith("$__CC2_"): + prim = "CC_LUT2" + elif name.startswith("$__CC5_") or (name.startswith("$__CC4_") and cost == 12): + prim = "CC_L2T5" + else: + prim = "CC_L2T4" + ports = {} + params = {} + lut_prims[prim].map(expr, params, ports) + print("", file=vf) + print("module \\%s (input %s, output Y);" % (name, + ", ".join(sorted(set(x for x in ports.values() if x)))), file=vf) + print(" %s #(" % prim, file=vf) + for k, v in sorted(params.items(), key=lambda x: x[0]): + print(" .%s(%s)," % (k, v), file=vf) + print(" ) _TECHMAP_REPLACE_ (", file=vf) + print(" %s," % ", ".join(".%s(%s)" % (k, v) for k, v in sorted(ports.items(), key=lambda x:x[0])), + file=vf) + print(" .O(Y)", file=vf) + print(" );", file=vf) + print("endmodule", file=vf) diff --git a/techlibs/gatemate/synth_gatemate.cc b/techlibs/gatemate/synth_gatemate.cc index 93b16b2e0..dd4fde643 100644 --- a/techlibs/gatemate/synth_gatemate.cc +++ b/techlibs/gatemate/synth_gatemate.cc @@ -67,7 +67,10 @@ struct SynthGateMatePass : public ScriptPass log("\n"); log(" -nomx8, -nomx4\n"); log(" do not use CC_MX{8,4} multiplexer cells in output netlist.\n"); - log("\n");; + log("\n"); + log(" -luttree\n"); + log(" use new LUT tree mapping approach (EXPERIMENTAL).\n"); + log("\n"); log(" -dff\n"); log(" run 'abc' with -dff option\n"); log("\n"); @@ -87,7 +90,7 @@ struct SynthGateMatePass : public ScriptPass } string top_opt, vlog_file, json_file; - bool noflatten, nobram, noaddf, nomult, nomx4, nomx8, dff, retime, noiopad, noclkbuf; + bool noflatten, nobram, noaddf, nomult, nomx4, nomx8, luttree, dff, retime, noiopad, noclkbuf; void clear_flags() override { @@ -100,6 +103,7 @@ struct SynthGateMatePass : public ScriptPass nomult = false; nomx4 = false; nomx8 = false; + luttree = false; dff = false; retime = false; noiopad = false; @@ -158,6 +162,10 @@ struct SynthGateMatePass : public ScriptPass nomx8 = true; continue; } + if (args[argidx] == "-luttree") { + luttree = true; + continue; + } if (args[argidx] == "-dff") { dff = true; continue; @@ -298,11 +306,23 @@ struct SynthGateMatePass : public ScriptPass if (check_label("map_luts")) { - std::string abc_args = " -dress -lut 4"; - if (dff) { - abc_args += " -dff"; + if (luttree || help_mode) { + std::string abc_args = " -genlib +/gatemate/lut_tree_cells.genlib"; + if (dff) { + abc_args += " -dff"; + } + run("abc " + abc_args, "(with -luttree)"); + run("techmap -map +/gatemate/lut_tree_map.v", "(with -luttree)"); + run("gatemate_foldinv", "(with -luttree)"); + run("techmap -map +/gatemate/inv_map.v", "(with -luttree)"); + } + if (!luttree || help_mode) { + std::string abc_args = " -dress -lut 4"; + if (dff) { + abc_args += " -dff"; + } + run("abc " + abc_args, "(without -luttree)"); } - run("abc " + abc_args); run("clean"); } -- cgit v1.2.3 From 48efc9b75c349beae615b8284cc3e23ebad28773 Mon Sep 17 00:00:00 2001 From: gatecat Date: Mon, 10 Jan 2022 09:05:01 +0000 Subject: gatemate: Add test for LUT tree mapping Signed-off-by: gatecat --- tests/arch/gatemate/gen_luttrees.py | 48 +++ tests/arch/gatemate/luttrees.v | 752 ++++++++++++++++++++++++++++++++++++ tests/arch/gatemate/luttrees.ys | 13 + 3 files changed, 813 insertions(+) create mode 100644 tests/arch/gatemate/gen_luttrees.py create mode 100644 tests/arch/gatemate/luttrees.v create mode 100644 tests/arch/gatemate/luttrees.ys diff --git a/tests/arch/gatemate/gen_luttrees.py b/tests/arch/gatemate/gen_luttrees.py new file mode 100644 index 000000000..27d2225a2 --- /dev/null +++ b/tests/arch/gatemate/gen_luttrees.py @@ -0,0 +1,48 @@ +from random import Random + +def main(): + r = Random(1) + + N = 750 + with open("tests/arch/gatemate/luttrees.v", "w") as v: + print(f"module luttrees(input [{N-1}:0] a, b, c, d, e, output [{N-1}:0] q);", file=v) + for i in range(N): + def f(): + return r.choice(["&", "|", "^"]) + + def a(x): + return f"({r.choice(['', '!'])}{x}[{i}])" + + # Bias towards testing bigger functions + k = r.choice([2, 3, 4, 4, 4, 5, 5, 5]) + if k == 2: + expr = f"{a('a')}{f()}{a('b')}" + elif k == 3: + expr = f"({a('a')}{f()}{a('b')}){f()}{a('c')}" + elif k == 4: + # Two types of 4-input function + if r.choice([False, True]): + expr = f"(({a('a')}{f()}{a('b')}){f()}{a('c')}){f()}{a('d')}" + else: + expr = f"({a('a')}{f()}{a('b')}){f()}({a('c')}{f()}{a('d')})" + elif k == 5: + expr = f"(({a('a')}{f()}{a('b')}){f()}({a('c')}{f()}{a('d')})){f()}{a('e')}" + print(f" assign q[{i}] = {expr};", file=v) + print("endmodule", file=v) + with open("tests/arch/gatemate/luttrees.ys", "w") as s: + print(f""" +read_verilog luttrees.v +design -save read + +hierarchy -top luttrees +proc +equiv_opt -async2sync -assert -map +/gatemate/cells_sim.v synth_gatemate -noiopad -luttree -nomx4 -nomx8 # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd luttrees # Constrain all select calls below inside the top module + +select -assert-count {N} t:CC_LUT2 t:CC_L2T4 t:CC_L2T5 %% +select -assert-none t:CC_LUT2 t:CC_L2T4 t:CC_L2T5 %% t:* %D +""", file=s) + +if __name__ == '__main__': + main() diff --git a/tests/arch/gatemate/luttrees.v b/tests/arch/gatemate/luttrees.v new file mode 100644 index 000000000..7fc02916d --- /dev/null +++ b/tests/arch/gatemate/luttrees.v @@ -0,0 +1,752 @@ +module luttrees(input [749:0] a, b, c, d, e, output [749:0] q); + assign q[0] = ((!a[0])&(!b[0]))|((!c[0])^(!d[0])); + assign q[1] = ((!a[1])&(!b[1]))|((c[1])^(!d[1])); + assign q[2] = ((a[2])|(b[2]))&((c[2])^(d[2])); + assign q[3] = (((a[3])|(b[3]))^((c[3])|(!d[3])))^(e[3]); + assign q[4] = (((a[4])^(b[4]))|((!c[4])&(!d[4])))^(e[4]); + assign q[5] = (((a[5])^(!b[5]))^(!c[5]))^(d[5]); + assign q[6] = (((!a[6])^(!b[6]))^(c[6]))|(d[6]); + assign q[7] = (((!a[7])^(b[7]))|((!c[7])&(!d[7])))^(e[7]); + assign q[8] = (((!a[8])|(b[8]))|(c[8]))|(!d[8]); + assign q[9] = ((a[9])&(b[9]))^((c[9])|(!d[9])); + assign q[10] = (((!a[10])|(b[10]))|((c[10])^(d[10])))|(e[10]); + assign q[11] = (((!a[11])^(b[11]))^((!c[11])|(!d[11])))|(!e[11]); + assign q[12] = (!a[12])|(b[12]); + assign q[13] = ((a[13])&(!b[13]))&((c[13])&(d[13])); + assign q[14] = (((a[14])|(b[14]))|((c[14])^(d[14])))|(!e[14]); + assign q[15] = ((a[15])&(!b[15]))^(c[15]); + assign q[16] = (((!a[16])^(!b[16]))|(!c[16]))&(d[16]); + assign q[17] = (((!a[17])|(b[17]))|(c[17]))|(d[17]); + assign q[18] = (((a[18])&(b[18]))|((c[18])&(d[18])))|(!e[18]); + assign q[19] = (((a[19])^(b[19]))|(!c[19]))^(!d[19]); + assign q[20] = (!a[20])&(b[20]); + assign q[21] = (!a[21])&(b[21]); + assign q[22] = (((a[22])|(!b[22]))&(c[22]))^(d[22]); + assign q[23] = (((a[23])^(b[23]))|(c[23]))|(d[23]); + assign q[24] = (((a[24])|(b[24]))^(!c[24]))|(!d[24]); + assign q[25] = (!a[25])^(!b[25]); + assign q[26] = ((a[26])&(!b[26]))^((c[26])|(!d[26])); + assign q[27] = (((a[27])|(!b[27]))^(!c[27]))^(d[27]); + assign q[28] = ((a[28])&(b[28]))&(c[28]); + assign q[29] = (((!a[29])^(!b[29]))|(!c[29]))|(d[29]); + assign q[30] = ((!a[30])&(b[30]))|((c[30])|(d[30])); + assign q[31] = (((a[31])&(!b[31]))&((!c[31])&(d[31])))^(e[31]); + assign q[32] = (((!a[32])^(b[32]))|(!c[32]))&(d[32]); + assign q[33] = ((a[33])&(!b[33]))&((c[33])&(d[33])); + assign q[34] = (((a[34])&(!b[34]))&((c[34])&(d[34])))|(!e[34]); + assign q[35] = (((!a[35])|(b[35]))&(!c[35]))&(d[35]); + assign q[36] = (!a[36])^(!b[36]); + assign q[37] = (((!a[37])|(!b[37]))&((c[37])|(!d[37])))&(!e[37]); + assign q[38] = (((!a[38])|(b[38]))^(c[38]))|(d[38]); + assign q[39] = (((a[39])|(b[39]))|(c[39]))^(!d[39]); + assign q[40] = (((!a[40])&(!b[40]))&(!c[40]))^(!d[40]); + assign q[41] = (((a[41])^(b[41]))&(c[41]))&(d[41]); + assign q[42] = (((a[42])|(b[42]))^((c[42])&(d[42])))|(!e[42]); + assign q[43] = (((!a[43])&(b[43]))^((!c[43])&(d[43])))&(e[43]); + assign q[44] = (((!a[44])&(!b[44]))&(c[44]))&(d[44]); + assign q[45] = (((a[45])&(!b[45]))|((c[45])&(d[45])))|(e[45]); + assign q[46] = (((!a[46])^(!b[46]))^((!c[46])^(!d[46])))&(!e[46]); + assign q[47] = (((a[47])|(!b[47]))&((!c[47])^(d[47])))&(!e[47]); + assign q[48] = ((a[48])|(!b[48]))|((!c[48])&(d[48])); + assign q[49] = (((a[49])&(!b[49]))^(!c[49]))^(d[49]); + assign q[50] = (((!a[50])^(!b[50]))&(!c[50]))|(!d[50]); + assign q[51] = ((a[51])^(!b[51]))&((c[51])|(!d[51])); + assign q[52] = (((a[52])^(!b[52]))^(c[52]))&(!d[52]); + assign q[53] = ((!a[53])|(b[53]))^((c[53])|(!d[53])); + assign q[54] = (((!a[54])^(b[54]))^((c[54])^(d[54])))|(e[54]); + assign q[55] = ((a[55])^(b[55]))|((c[55])|(!d[55])); + assign q[56] = (((a[56])|(!b[56]))&((!c[56])&(d[56])))|(!e[56]); + assign q[57] = ((!a[57])|(b[57]))|(c[57]); + assign q[58] = (((a[58])&(b[58]))|(c[58]))&(!d[58]); + assign q[59] = ((!a[59])|(!b[59]))^((!c[59])&(!d[59])); + assign q[60] = (((!a[60])&(b[60]))^((!c[60])&(!d[60])))&(e[60]); + assign q[61] = ((a[61])^(!b[61]))^(c[61]); + assign q[62] = ((!a[62])^(!b[62]))|(!c[62]); + assign q[63] = (((a[63])&(!b[63]))^((!c[63])|(!d[63])))^(!e[63]); + assign q[64] = (((!a[64])&(!b[64]))|((c[64])^(d[64])))|(e[64]); + assign q[65] = (((!a[65])^(!b[65]))^((c[65])|(d[65])))|(e[65]); + assign q[66] = (((!a[66])|(!b[66]))^((c[66])|(d[66])))^(!e[66]); + assign q[67] = (!a[67])^(b[67]); + assign q[68] = (((!a[68])&(b[68]))^((c[68])|(!d[68])))^(!e[68]); + assign q[69] = ((!a[69])|(!b[69]))&((!c[69])^(d[69])); + assign q[70] = ((!a[70])&(!b[70]))&((!c[70])&(d[70])); + assign q[71] = ((!a[71])^(!b[71]))^((!c[71])&(d[71])); + assign q[72] = (((!a[72])&(b[72]))^(!c[72]))|(d[72]); + assign q[73] = (((!a[73])|(b[73]))|(!c[73]))&(!d[73]); + assign q[74] = (((a[74])|(b[74]))^(c[74]))^(!d[74]); + assign q[75] = (((!a[75])&(!b[75]))&((c[75])^(d[75])))^(!e[75]); + assign q[76] = (((!a[76])^(b[76]))&(c[76]))^(!d[76]); + assign q[77] = (((!a[77])|(b[77]))&((c[77])^(!d[77])))&(e[77]); + assign q[78] = (((!a[78])|(b[78]))&(c[78]))&(d[78]); + assign q[79] = ((!a[79])^(!b[79]))|((!c[79])&(d[79])); + assign q[80] = ((a[80])|(b[80]))|(!c[80]); + assign q[81] = (((a[81])&(b[81]))|((!c[81])^(!d[81])))&(!e[81]); + assign q[82] = (((!a[82])^(b[82]))&(c[82]))&(d[82]); + assign q[83] = (!a[83])|(!b[83]); + assign q[84] = ((!a[84])&(b[84]))&((c[84])|(d[84])); + assign q[85] = (!a[85])|(b[85]); + assign q[86] = ((!a[86])^(!b[86]))&(c[86]); + assign q[87] = (a[87])&(!b[87]); + assign q[88] = ((!a[88])&(b[88]))&(!c[88]); + assign q[89] = (((a[89])^(!b[89]))|(!c[89]))^(!d[89]); + assign q[90] = ((a[90])&(b[90]))|((!c[90])^(d[90])); + assign q[91] = (((!a[91])^(b[91]))^((!c[91])^(d[91])))^(!e[91]); + assign q[92] = ((!a[92])&(b[92]))&(c[92]); + assign q[93] = (((a[93])&(b[93]))^(!c[93]))^(!d[93]); + assign q[94] = ((!a[94])&(b[94]))^(c[94]); + assign q[95] = (((a[95])|(!b[95]))&((!c[95])&(!d[95])))|(e[95]); + assign q[96] = ((!a[96])&(!b[96]))|((c[96])|(!d[96])); + assign q[97] = ((!a[97])&(!b[97]))&(c[97]); + assign q[98] = (((!a[98])^(!b[98]))^((!c[98])&(d[98])))^(!e[98]); + assign q[99] = (!a[99])^(b[99]); + assign q[100] = (((!a[100])^(!b[100]))&(!c[100]))|(d[100]); + assign q[101] = ((a[101])|(!b[101]))|(!c[101]); + assign q[102] = (((!a[102])|(!b[102]))^((c[102])^(d[102])))&(!e[102]); + assign q[103] = (((!a[103])^(b[103]))|((!c[103])|(!d[103])))|(!e[103]); + assign q[104] = ((a[104])&(b[104]))^(!c[104]); + assign q[105] = ((!a[105])|(!b[105]))|((!c[105])|(!d[105])); + assign q[106] = ((a[106])|(b[106]))^((c[106])&(d[106])); + assign q[107] = (((a[107])&(!b[107]))^((c[107])&(!d[107])))&(e[107]); + assign q[108] = ((a[108])^(b[108]))^(!c[108]); + assign q[109] = (!a[109])|(!b[109]); + assign q[110] = ((!a[110])&(!b[110]))|((!c[110])^(d[110])); + assign q[111] = (((a[111])|(!b[111]))&((c[111])^(!d[111])))^(!e[111]); + assign q[112] = ((!a[112])^(!b[112]))&(!c[112]); + assign q[113] = (((a[113])&(!b[113]))^((c[113])^(d[113])))|(!e[113]); + assign q[114] = (((!a[114])^(!b[114]))|(!c[114]))&(!d[114]); + assign q[115] = ((!a[115])^(b[115]))|((c[115])|(!d[115])); + assign q[116] = (((!a[116])^(b[116]))&((c[116])&(!d[116])))|(!e[116]); + assign q[117] = (((!a[117])|(!b[117]))|(c[117]))|(!d[117]); + assign q[118] = (((a[118])&(b[118]))|(!c[118]))&(!d[118]); + assign q[119] = (((!a[119])^(!b[119]))^((!c[119])^(!d[119])))|(!e[119]); + assign q[120] = (((a[120])^(!b[120]))|((!c[120])&(d[120])))&(e[120]); + assign q[121] = ((a[121])&(!b[121]))&((!c[121])&(!d[121])); + assign q[122] = ((a[122])|(b[122]))^((c[122])^(!d[122])); + assign q[123] = (((a[123])^(b[123]))^((!c[123])^(d[123])))|(!e[123]); + assign q[124] = (((a[124])&(b[124]))|(c[124]))^(!d[124]); + assign q[125] = (((!a[125])&(!b[125]))&(c[125]))|(d[125]); + assign q[126] = (((!a[126])^(!b[126]))|(c[126]))^(!d[126]); + assign q[127] = (((a[127])&(!b[127]))^((!c[127])&(!d[127])))|(e[127]); + assign q[128] = (((!a[128])^(b[128]))|(c[128]))&(!d[128]); + assign q[129] = (((a[129])^(b[129]))|(!c[129]))|(!d[129]); + assign q[130] = (((!a[130])&(!b[130]))|(!c[130]))&(!d[130]); + assign q[131] = ((!a[131])^(b[131]))&((!c[131])^(d[131])); + assign q[132] = (((!a[132])|(!b[132]))&(c[132]))&(!d[132]); + assign q[133] = ((a[133])^(b[133]))^((c[133])&(d[133])); + assign q[134] = (((!a[134])&(b[134]))|(c[134]))&(d[134]); + assign q[135] = (((!a[135])^(!b[135]))&(c[135]))|(!d[135]); + assign q[136] = ((!a[136])&(b[136]))|((c[136])&(d[136])); + assign q[137] = (((a[137])|(b[137]))|(c[137]))&(d[137]); + assign q[138] = (((!a[138])^(b[138]))&((!c[138])|(d[138])))^(!e[138]); + assign q[139] = ((!a[139])^(b[139]))^(!c[139]); + assign q[140] = (((a[140])^(!b[140]))^((!c[140])^(!d[140])))|(e[140]); + assign q[141] = ((a[141])^(b[141]))&((c[141])&(!d[141])); + assign q[142] = ((!a[142])^(!b[142]))^((!c[142])|(d[142])); + assign q[143] = (((a[143])^(!b[143]))&((!c[143])^(d[143])))^(!e[143]); + assign q[144] = (((a[144])&(b[144]))^((c[144])^(d[144])))|(!e[144]); + assign q[145] = (((!a[145])&(b[145]))|((!c[145])|(d[145])))^(e[145]); + assign q[146] = (((a[146])^(b[146]))^(c[146]))|(d[146]); + assign q[147] = (((a[147])|(!b[147]))|((!c[147])|(!d[147])))^(!e[147]); + assign q[148] = (a[148])|(b[148]); + assign q[149] = (a[149])&(b[149]); + assign q[150] = (((!a[150])^(!b[150]))|((c[150])^(d[150])))&(!e[150]); + assign q[151] = ((a[151])^(!b[151]))|((!c[151])|(d[151])); + assign q[152] = (((!a[152])|(!b[152]))|((!c[152])|(d[152])))^(e[152]); + assign q[153] = (!a[153])^(b[153]); + assign q[154] = (((!a[154])^(b[154]))^(c[154]))|(d[154]); + assign q[155] = (((a[155])|(b[155]))&((c[155])|(!d[155])))^(e[155]); + assign q[156] = (((!a[156])|(!b[156]))^((c[156])|(!d[156])))|(e[156]); + assign q[157] = (((!a[157])&(b[157]))&((!c[157])|(d[157])))&(e[157]); + assign q[158] = (((!a[158])^(!b[158]))&(c[158]))^(d[158]); + assign q[159] = ((!a[159])|(b[159]))^((!c[159])&(d[159])); + assign q[160] = (((a[160])^(b[160]))|((c[160])&(d[160])))&(!e[160]); + assign q[161] = (a[161])|(b[161]); + assign q[162] = (a[162])^(b[162]); + assign q[163] = (((!a[163])&(b[163]))|(c[163]))^(d[163]); + assign q[164] = (((a[164])^(b[164]))&((c[164])|(!d[164])))|(!e[164]); + assign q[165] = ((!a[165])^(!b[165]))^((!c[165])^(d[165])); + assign q[166] = (((!a[166])&(!b[166]))|((!c[166])&(!d[166])))^(!e[166]); + assign q[167] = ((!a[167])|(b[167]))|((!c[167])|(!d[167])); + assign q[168] = (((!a[168])^(!b[168]))&((c[168])&(!d[168])))&(e[168]); + assign q[169] = ((a[169])^(!b[169]))^(c[169]); + assign q[170] = (((!a[170])^(b[170]))&(c[170]))&(d[170]); + assign q[171] = (!a[171])|(!b[171]); + assign q[172] = ((a[172])&(!b[172]))&((!c[172])&(!d[172])); + assign q[173] = (((a[173])&(!b[173]))^((c[173])|(!d[173])))^(!e[173]); + assign q[174] = ((!a[174])&(!b[174]))&(!c[174]); + assign q[175] = ((!a[175])|(!b[175]))^(c[175]); + assign q[176] = (!a[176])&(b[176]); + assign q[177] = ((a[177])|(b[177]))^(c[177]); + assign q[178] = (((a[178])^(b[178]))|((c[178])^(!d[178])))^(e[178]); + assign q[179] = ((a[179])^(!b[179]))^(!c[179]); + assign q[180] = (((a[180])^(b[180]))^(c[180]))|(!d[180]); + assign q[181] = (((!a[181])|(!b[181]))&((c[181])&(d[181])))|(e[181]); + assign q[182] = (((a[182])|(!b[182]))&((c[182])&(d[182])))|(!e[182]); + assign q[183] = ((a[183])^(!b[183]))^((!c[183])&(d[183])); + assign q[184] = (((a[184])|(b[184]))|((c[184])^(d[184])))&(!e[184]); + assign q[185] = (((a[185])^(b[185]))^((!c[185])&(!d[185])))^(!e[185]); + assign q[186] = (((!a[186])|(!b[186]))&((!c[186])&(!d[186])))|(!e[186]); + assign q[187] = (((a[187])^(!b[187]))|(!c[187]))^(d[187]); + assign q[188] = ((a[188])^(b[188]))&(!c[188]); + assign q[189] = (((!a[189])^(b[189]))^((!c[189])^(d[189])))|(e[189]); + assign q[190] = (((!a[190])^(b[190]))&((!c[190])|(d[190])))&(e[190]); + assign q[191] = ((!a[191])|(!b[191]))|(!c[191]); + assign q[192] = (((a[192])^(b[192]))^(c[192]))|(!d[192]); + assign q[193] = ((a[193])^(b[193]))|((!c[193])&(d[193])); + assign q[194] = (((a[194])&(b[194]))|(!c[194]))&(!d[194]); + assign q[195] = ((!a[195])|(!b[195]))^((c[195])&(!d[195])); + assign q[196] = (((a[196])&(!b[196]))|((c[196])^(d[196])))^(!e[196]); + assign q[197] = ((a[197])&(b[197]))^((c[197])^(!d[197])); + assign q[198] = (((a[198])&(!b[198]))|((!c[198])^(!d[198])))&(e[198]); + assign q[199] = (!a[199])&(b[199]); + assign q[200] = ((a[200])&(b[200]))^((c[200])&(d[200])); + assign q[201] = (((!a[201])&(!b[201]))^(!c[201]))|(!d[201]); + assign q[202] = ((a[202])^(b[202]))&(!c[202]); + assign q[203] = (((!a[203])|(b[203]))|((c[203])&(!d[203])))^(!e[203]); + assign q[204] = (((a[204])^(!b[204]))&((!c[204])^(!d[204])))^(!e[204]); + assign q[205] = (((a[205])|(!b[205]))^((!c[205])^(!d[205])))|(!e[205]); + assign q[206] = (a[206])|(!b[206]); + assign q[207] = (((a[207])^(!b[207]))&((!c[207])|(d[207])))|(!e[207]); + assign q[208] = (a[208])|(b[208]); + assign q[209] = ((!a[209])|(b[209]))|((!c[209])|(d[209])); + assign q[210] = ((!a[210])&(b[210]))&((!c[210])|(!d[210])); + assign q[211] = ((a[211])^(!b[211]))|((!c[211])|(!d[211])); + assign q[212] = (((a[212])&(!b[212]))&((c[212])^(d[212])))^(e[212]); + assign q[213] = (((!a[213])&(b[213]))^(!c[213]))^(!d[213]); + assign q[214] = (!a[214])|(!b[214]); + assign q[215] = ((a[215])|(!b[215]))^((!c[215])^(!d[215])); + assign q[216] = (((a[216])^(!b[216]))^((!c[216])|(d[216])))|(e[216]); + assign q[217] = (((a[217])^(b[217]))^((!c[217])|(!d[217])))&(e[217]); + assign q[218] = ((a[218])&(!b[218]))&(c[218]); + assign q[219] = ((a[219])|(b[219]))&((c[219])&(d[219])); + assign q[220] = (((!a[220])&(b[220]))^((c[220])|(d[220])))|(!e[220]); + assign q[221] = ((a[221])&(!b[221]))&((c[221])^(!d[221])); + assign q[222] = (!a[222])|(!b[222]); + assign q[223] = ((a[223])^(b[223]))^(c[223]); + assign q[224] = ((a[224])&(!b[224]))&((c[224])|(d[224])); + assign q[225] = ((!a[225])&(b[225]))&(!c[225]); + assign q[226] = (((a[226])^(b[226]))|((c[226])&(d[226])))&(e[226]); + assign q[227] = ((a[227])&(b[227]))|((!c[227])^(!d[227])); + assign q[228] = ((!a[228])&(!b[228]))|((!c[228])|(!d[228])); + assign q[229] = (((a[229])|(b[229]))|((!c[229])&(d[229])))&(e[229]); + assign q[230] = (((!a[230])^(!b[230]))|((!c[230])|(!d[230])))|(!e[230]); + assign q[231] = (((!a[231])|(b[231]))|((c[231])|(d[231])))|(e[231]); + assign q[232] = ((!a[232])^(b[232]))&((c[232])&(!d[232])); + assign q[233] = (((!a[233])&(!b[233]))|(!c[233]))&(!d[233]); + assign q[234] = (((!a[234])&(b[234]))^(!c[234]))&(d[234]); + assign q[235] = (((a[235])&(b[235]))^((!c[235])^(!d[235])))^(!e[235]); + assign q[236] = (((!a[236])^(b[236]))&((!c[236])&(!d[236])))^(e[236]); + assign q[237] = (a[237])|(!b[237]); + assign q[238] = (((a[238])|(b[238]))&((!c[238])^(d[238])))&(e[238]); + assign q[239] = ((!a[239])^(!b[239]))&((c[239])&(d[239])); + assign q[240] = (((!a[240])^(!b[240]))&(!c[240]))&(!d[240]); + assign q[241] = ((!a[241])&(b[241]))&(c[241]); + assign q[242] = ((a[242])|(!b[242]))&((c[242])|(d[242])); + assign q[243] = ((a[243])|(b[243]))^((!c[243])&(d[243])); + assign q[244] = (((!a[244])^(b[244]))&(!c[244]))|(!d[244]); + assign q[245] = (((a[245])^(!b[245]))^(!c[245]))^(!d[245]); + assign q[246] = ((!a[246])|(!b[246]))&(!c[246]); + assign q[247] = ((!a[247])&(b[247]))|(c[247]); + assign q[248] = (((!a[248])|(!b[248]))|((!c[248])&(!d[248])))&(!e[248]); + assign q[249] = (a[249])|(!b[249]); + assign q[250] = (((!a[250])^(!b[250]))^(!c[250]))^(!d[250]); + assign q[251] = (((a[251])|(b[251]))|(!c[251]))^(d[251]); + assign q[252] = (((!a[252])&(!b[252]))^((c[252])&(d[252])))&(e[252]); + assign q[253] = (!a[253])^(!b[253]); + assign q[254] = (((a[254])^(!b[254]))|((c[254])|(!d[254])))&(!e[254]); + assign q[255] = (!a[255])|(!b[255]); + assign q[256] = (((a[256])|(!b[256]))&(c[256]))&(!d[256]); + assign q[257] = (!a[257])^(!b[257]); + assign q[258] = (((!a[258])&(b[258]))^(c[258]))|(d[258]); + assign q[259] = (((!a[259])&(!b[259]))|(c[259]))&(!d[259]); + assign q[260] = ((!a[260])&(!b[260]))|((!c[260])^(!d[260])); + assign q[261] = (((a[261])|(b[261]))^(c[261]))|(d[261]); + assign q[262] = (((!a[262])^(b[262]))^((!c[262])|(!d[262])))|(e[262]); + assign q[263] = (a[263])^(b[263]); + assign q[264] = ((!a[264])&(!b[264]))|(c[264]); + assign q[265] = (((!a[265])^(b[265]))^((c[265])^(!d[265])))|(!e[265]); + assign q[266] = (((a[266])^(!b[266]))&(c[266]))^(d[266]); + assign q[267] = ((a[267])|(!b[267]))|(!c[267]); + assign q[268] = ((!a[268])&(!b[268]))|(!c[268]); + assign q[269] = (((!a[269])^(b[269]))&((!c[269])^(!d[269])))^(!e[269]); + assign q[270] = (((a[270])|(b[270]))^(c[270]))&(d[270]); + assign q[271] = (((a[271])&(b[271]))|((c[271])|(d[271])))|(!e[271]); + assign q[272] = (((a[272])|(!b[272]))^(!c[272]))|(!d[272]); + assign q[273] = (((!a[273])|(b[273]))&((!c[273])&(!d[273])))&(!e[273]); + assign q[274] = ((a[274])^(!b[274]))|(!c[274]); + assign q[275] = (((!a[275])^(!b[275]))|((!c[275])^(!d[275])))^(e[275]); + assign q[276] = ((a[276])^(b[276]))&((!c[276])^(d[276])); + assign q[277] = (((!a[277])&(!b[277]))|((!c[277])^(!d[277])))&(!e[277]); + assign q[278] = (((!a[278])^(!b[278]))^(c[278]))&(!d[278]); + assign q[279] = (((a[279])&(b[279]))^((!c[279])|(d[279])))^(!e[279]); + assign q[280] = ((!a[280])&(!b[280]))&(!c[280]); + assign q[281] = ((a[281])|(b[281]))|((!c[281])|(!d[281])); + assign q[282] = ((a[282])&(b[282]))&((c[282])|(d[282])); + assign q[283] = (((a[283])|(!b[283]))^((c[283])&(!d[283])))&(e[283]); + assign q[284] = (((!a[284])&(b[284]))&(!c[284]))^(d[284]); + assign q[285] = (((a[285])|(!b[285]))&(!c[285]))|(d[285]); + assign q[286] = (((a[286])^(b[286]))&((c[286])^(!d[286])))&(!e[286]); + assign q[287] = ((a[287])&(!b[287]))|((c[287])|(!d[287])); + assign q[288] = ((!a[288])|(!b[288]))|((!c[288])|(!d[288])); + assign q[289] = ((a[289])&(b[289]))&((c[289])&(!d[289])); + assign q[290] = (((!a[290])^(b[290]))&((c[290])^(d[290])))&(!e[290]); + assign q[291] = (((a[291])&(!b[291]))|(!c[291]))^(d[291]); + assign q[292] = (((a[292])^(!b[292]))^((c[292])|(d[292])))&(e[292]); + assign q[293] = (((a[293])&(!b[293]))&((c[293])|(d[293])))|(e[293]); + assign q[294] = (((a[294])^(!b[294]))&((!c[294])^(d[294])))&(!e[294]); + assign q[295] = (((a[295])^(!b[295]))|((!c[295])|(d[295])))&(e[295]); + assign q[296] = (((a[296])&(!b[296]))&((c[296])&(d[296])))&(!e[296]); + assign q[297] = ((!a[297])|(b[297]))^((!c[297])^(!d[297])); + assign q[298] = (((a[298])^(b[298]))|((!c[298])|(d[298])))|(!e[298]); + assign q[299] = (((!a[299])^(b[299]))|((c[299])^(!d[299])))|(!e[299]); + assign q[300] = (((!a[300])^(!b[300]))^(!c[300]))|(d[300]); + assign q[301] = ((a[301])&(!b[301]))&((!c[301])|(!d[301])); + assign q[302] = ((a[302])^(b[302]))|((c[302])|(!d[302])); + assign q[303] = (((!a[303])&(b[303]))^((c[303])|(d[303])))|(!e[303]); + assign q[304] = (!a[304])^(b[304]); + assign q[305] = (((a[305])&(!b[305]))^((!c[305])&(!d[305])))^(!e[305]); + assign q[306] = (a[306])&(b[306]); + assign q[307] = ((a[307])&(!b[307]))&(c[307]); + assign q[308] = ((a[308])&(!b[308]))^((!c[308])|(d[308])); + assign q[309] = ((a[309])^(!b[309]))&((c[309])|(!d[309])); + assign q[310] = (((!a[310])|(b[310]))&((c[310])^(d[310])))^(!e[310]); + assign q[311] = (((!a[311])|(b[311]))&((c[311])&(d[311])))|(e[311]); + assign q[312] = (((!a[312])&(b[312]))|((c[312])^(!d[312])))&(!e[312]); + assign q[313] = (!a[313])|(!b[313]); + assign q[314] = ((a[314])^(!b[314]))^((c[314])|(!d[314])); + assign q[315] = (a[315])&(!b[315]); + assign q[316] = ((!a[316])^(!b[316]))&(!c[316]); + assign q[317] = ((a[317])&(!b[317]))^(c[317]); + assign q[318] = (((!a[318])^(!b[318]))|(!c[318]))&(!d[318]); + assign q[319] = (((a[319])&(!b[319]))|(!c[319]))^(d[319]); + assign q[320] = (((!a[320])^(!b[320]))|(c[320]))|(d[320]); + assign q[321] = ((a[321])|(!b[321]))|((c[321])|(d[321])); + assign q[322] = ((!a[322])^(!b[322]))&(!c[322]); + assign q[323] = (((!a[323])&(b[323]))|(c[323]))|(d[323]); + assign q[324] = ((!a[324])&(!b[324]))^((c[324])|(d[324])); + assign q[325] = ((a[325])&(!b[325]))|(!c[325]); + assign q[326] = ((!a[326])^(!b[326]))|(c[326]); + assign q[327] = (((a[327])|(b[327]))&((c[327])|(!d[327])))^(!e[327]); + assign q[328] = ((!a[328])|(b[328]))&((c[328])&(d[328])); + assign q[329] = (((a[329])&(b[329]))^(c[329]))|(!d[329]); + assign q[330] = ((a[330])|(b[330]))|((c[330])^(!d[330])); + assign q[331] = (((!a[331])|(b[331]))&(c[331]))&(d[331]); + assign q[332] = (((!a[332])&(b[332]))|((!c[332])^(d[332])))&(e[332]); + assign q[333] = (((a[333])^(!b[333]))|(!c[333]))|(!d[333]); + assign q[334] = ((a[334])&(!b[334]))&((c[334])&(!d[334])); + assign q[335] = (((!a[335])&(b[335]))^((c[335])&(d[335])))&(e[335]); + assign q[336] = (!a[336])^(b[336]); + assign q[337] = (((a[337])^(b[337]))&(c[337]))&(d[337]); + assign q[338] = (((a[338])^(!b[338]))&(!c[338]))&(!d[338]); + assign q[339] = (((!a[339])^(!b[339]))|((!c[339])|(d[339])))&(!e[339]); + assign q[340] = (((a[340])^(b[340]))^((c[340])^(d[340])))|(e[340]); + assign q[341] = (((!a[341])&(!b[341]))^(!c[341]))^(d[341]); + assign q[342] = (a[342])^(!b[342]); + assign q[343] = (((!a[343])^(b[343]))&((c[343])|(!d[343])))|(e[343]); + assign q[344] = ((a[344])&(b[344]))&((!c[344])&(d[344])); + assign q[345] = (((!a[345])&(b[345]))&((c[345])^(!d[345])))|(e[345]); + assign q[346] = (((a[346])^(!b[346]))&(c[346]))&(!d[346]); + assign q[347] = (((!a[347])^(!b[347]))|((c[347])|(!d[347])))|(!e[347]); + assign q[348] = (((a[348])|(b[348]))&((!c[348])&(d[348])))|(!e[348]); + assign q[349] = (!a[349])&(b[349]); + assign q[350] = (((!a[350])^(b[350]))|((c[350])|(!d[350])))&(e[350]); + assign q[351] = (((!a[351])^(!b[351]))^((c[351])|(!d[351])))&(!e[351]); + assign q[352] = ((!a[352])|(b[352]))^(c[352]); + assign q[353] = (((a[353])&(!b[353]))^((c[353])&(!d[353])))|(!e[353]); + assign q[354] = (((!a[354])^(b[354]))^((!c[354])^(d[354])))^(e[354]); + assign q[355] = (a[355])|(b[355]); + assign q[356] = (((a[356])^(!b[356]))^(!c[356]))&(!d[356]); + assign q[357] = (((a[357])&(!b[357]))^((c[357])&(!d[357])))^(e[357]); + assign q[358] = (((a[358])&(b[358]))&((!c[358])&(d[358])))|(e[358]); + assign q[359] = (((a[359])&(!b[359]))&((!c[359])^(!d[359])))&(e[359]); + assign q[360] = (((!a[360])|(!b[360]))|((!c[360])|(d[360])))&(!e[360]); + assign q[361] = (((a[361])|(b[361]))^((c[361])|(!d[361])))^(!e[361]); + assign q[362] = (((!a[362])|(!b[362]))|(c[362]))|(d[362]); + assign q[363] = ((a[363])|(!b[363]))&((!c[363])^(!d[363])); + assign q[364] = (((a[364])&(!b[364]))&((c[364])&(d[364])))|(e[364]); + assign q[365] = ((a[365])|(!b[365]))&((c[365])|(d[365])); + assign q[366] = (((a[366])|(!b[366]))&((!c[366])|(!d[366])))^(!e[366]); + assign q[367] = ((a[367])^(!b[367]))^((!c[367])|(!d[367])); + assign q[368] = (((!a[368])&(b[368]))&((!c[368])|(!d[368])))&(!e[368]); + assign q[369] = ((a[369])^(b[369]))|((c[369])|(d[369])); + assign q[370] = (((a[370])^(b[370]))^(!c[370]))|(!d[370]); + assign q[371] = (((a[371])^(b[371]))&((!c[371])&(d[371])))&(!e[371]); + assign q[372] = (((!a[372])|(!b[372]))|((!c[372])&(d[372])))&(!e[372]); + assign q[373] = ((a[373])&(b[373]))&((!c[373])&(!d[373])); + assign q[374] = (((!a[374])^(!b[374]))^((!c[374])&(!d[374])))|(e[374]); + assign q[375] = ((!a[375])&(b[375]))^(!c[375]); + assign q[376] = (!a[376])|(b[376]); + assign q[377] = (((!a[377])^(b[377]))^((!c[377])^(!d[377])))^(e[377]); + assign q[378] = (((a[378])|(!b[378]))^((c[378])^(d[378])))&(!e[378]); + assign q[379] = (((a[379])|(b[379]))&((!c[379])^(!d[379])))^(e[379]); + assign q[380] = (((!a[380])^(!b[380]))^((c[380])|(!d[380])))&(!e[380]); + assign q[381] = (((!a[381])^(b[381]))^(c[381]))^(!d[381]); + assign q[382] = (((!a[382])^(b[382]))^(!c[382]))&(!d[382]); + assign q[383] = (((!a[383])&(!b[383]))&((c[383])^(d[383])))|(e[383]); + assign q[384] = (((a[384])&(b[384]))&((c[384])&(d[384])))^(e[384]); + assign q[385] = ((a[385])|(!b[385]))&(!c[385]); + assign q[386] = ((a[386])|(b[386]))&(!c[386]); + assign q[387] = (((!a[387])^(b[387]))|(c[387]))^(d[387]); + assign q[388] = (!a[388])&(!b[388]); + assign q[389] = ((a[389])^(b[389]))^(!c[389]); + assign q[390] = (((!a[390])|(b[390]))^(c[390]))|(d[390]); + assign q[391] = (!a[391])^(!b[391]); + assign q[392] = ((!a[392])^(b[392]))|(c[392]); + assign q[393] = (((!a[393])&(!b[393]))^((c[393])^(d[393])))^(e[393]); + assign q[394] = (((!a[394])^(b[394]))|(!c[394]))|(!d[394]); + assign q[395] = ((!a[395])&(!b[395]))^(!c[395]); + assign q[396] = ((a[396])^(b[396]))|((!c[396])|(d[396])); + assign q[397] = (((a[397])|(!b[397]))&((!c[397])&(d[397])))&(!e[397]); + assign q[398] = (((a[398])&(!b[398]))^((c[398])&(d[398])))|(!e[398]); + assign q[399] = (((!a[399])^(!b[399]))^((c[399])&(d[399])))|(!e[399]); + assign q[400] = (!a[400])&(b[400]); + assign q[401] = (((a[401])&(!b[401]))^(!c[401]))^(!d[401]); + assign q[402] = ((a[402])|(!b[402]))^((!c[402])^(!d[402])); + assign q[403] = (((!a[403])|(!b[403]))|((c[403])|(d[403])))^(!e[403]); + assign q[404] = (((!a[404])^(b[404]))&((c[404])&(d[404])))^(!e[404]); + assign q[405] = (((!a[405])^(b[405]))&(!c[405]))&(d[405]); + assign q[406] = (((!a[406])|(b[406]))|((c[406])^(!d[406])))&(!e[406]); + assign q[407] = (!a[407])|(b[407]); + assign q[408] = (((!a[408])&(!b[408]))|(!c[408]))&(!d[408]); + assign q[409] = (!a[409])^(!b[409]); + assign q[410] = (((!a[410])|(b[410]))|((!c[410])|(d[410])))|(!e[410]); + assign q[411] = (((!a[411])^(b[411]))|((c[411])&(d[411])))|(e[411]); + assign q[412] = ((!a[412])&(!b[412]))&((c[412])|(d[412])); + assign q[413] = (((!a[413])^(b[413]))^((c[413])&(!d[413])))&(!e[413]); + assign q[414] = (a[414])^(!b[414]); + assign q[415] = (((!a[415])^(b[415]))&(c[415]))|(!d[415]); + assign q[416] = ((!a[416])|(!b[416]))&(c[416]); + assign q[417] = (((!a[417])^(!b[417]))^((c[417])^(d[417])))|(!e[417]); + assign q[418] = ((!a[418])&(!b[418]))^((!c[418])&(!d[418])); + assign q[419] = (!a[419])&(!b[419]); + assign q[420] = ((a[420])^(!b[420]))|(!c[420]); + assign q[421] = ((!a[421])&(!b[421]))&((!c[421])^(d[421])); + assign q[422] = ((!a[422])^(b[422]))^((!c[422])&(!d[422])); + assign q[423] = (((a[423])|(b[423]))^((c[423])&(d[423])))^(!e[423]); + assign q[424] = (a[424])|(b[424]); + assign q[425] = (!a[425])^(b[425]); + assign q[426] = (!a[426])^(!b[426]); + assign q[427] = ((a[427])&(!b[427]))^((!c[427])^(!d[427])); + assign q[428] = (((!a[428])&(!b[428]))^(!c[428]))^(d[428]); + assign q[429] = (((!a[429])^(b[429]))&(c[429]))&(d[429]); + assign q[430] = ((!a[430])&(b[430]))^((c[430])^(d[430])); + assign q[431] = (((!a[431])|(b[431]))^((!c[431])|(d[431])))&(e[431]); + assign q[432] = (((!a[432])|(!b[432]))|((!c[432])^(d[432])))|(!e[432]); + assign q[433] = (((a[433])^(!b[433]))&(!c[433]))&(d[433]); + assign q[434] = ((!a[434])&(!b[434]))|((c[434])|(!d[434])); + assign q[435] = (!a[435])|(!b[435]); + assign q[436] = (((!a[436])^(!b[436]))&((!c[436])|(!d[436])))&(e[436]); + assign q[437] = (((!a[437])^(!b[437]))^(!c[437]))&(!d[437]); + assign q[438] = (!a[438])^(b[438]); + assign q[439] = ((a[439])^(!b[439]))|(c[439]); + assign q[440] = ((a[440])^(!b[440]))|((!c[440])&(!d[440])); + assign q[441] = (((a[441])&(b[441]))^((c[441])&(d[441])))|(e[441]); + assign q[442] = (!a[442])|(b[442]); + assign q[443] = (!a[443])^(b[443]); + assign q[444] = ((a[444])^(!b[444]))|((c[444])&(d[444])); + assign q[445] = (((a[445])|(!b[445]))&(c[445]))|(d[445]); + assign q[446] = ((a[446])&(b[446]))^((c[446])^(!d[446])); + assign q[447] = ((!a[447])&(!b[447]))^(!c[447]); + assign q[448] = (((!a[448])^(b[448]))&(c[448]))|(!d[448]); + assign q[449] = (((a[449])|(!b[449]))|((c[449])&(d[449])))|(!e[449]); + assign q[450] = (((!a[450])|(b[450]))|(c[450]))^(!d[450]); + assign q[451] = ((a[451])^(b[451]))|((c[451])^(d[451])); + assign q[452] = (((a[452])^(!b[452]))|(c[452]))|(d[452]); + assign q[453] = (!a[453])^(!b[453]); + assign q[454] = (((a[454])|(!b[454]))|(c[454]))^(d[454]); + assign q[455] = ((!a[455])&(b[455]))^((!c[455])|(!d[455])); + assign q[456] = (((a[456])^(!b[456]))|((c[456])^(d[456])))^(e[456]); + assign q[457] = (((a[457])&(!b[457]))^(c[457]))|(d[457]); + assign q[458] = (((!a[458])^(b[458]))^(c[458]))&(!d[458]); + assign q[459] = (((!a[459])&(b[459]))^((!c[459])&(!d[459])))&(e[459]); + assign q[460] = ((!a[460])^(!b[460]))|((c[460])&(!d[460])); + assign q[461] = ((a[461])&(!b[461]))&(c[461]); + assign q[462] = (((a[462])|(b[462]))^((c[462])^(d[462])))|(!e[462]); + assign q[463] = (((a[463])|(!b[463]))&((!c[463])|(d[463])))|(e[463]); + assign q[464] = (((!a[464])^(b[464]))&((!c[464])|(!d[464])))^(e[464]); + assign q[465] = ((!a[465])|(b[465]))&((c[465])&(d[465])); + assign q[466] = (((!a[466])^(b[466]))|((!c[466])&(d[466])))&(e[466]); + assign q[467] = (((!a[467])|(!b[467]))&((!c[467])&(!d[467])))^(!e[467]); + assign q[468] = ((!a[468])^(!b[468]))&((c[468])&(!d[468])); + assign q[469] = (((a[469])^(b[469]))^(c[469]))&(!d[469]); + assign q[470] = (((a[470])&(b[470]))^(c[470]))&(d[470]); + assign q[471] = (((!a[471])&(b[471]))^(c[471]))&(!d[471]); + assign q[472] = (((!a[472])|(b[472]))|((!c[472])|(!d[472])))|(!e[472]); + assign q[473] = (((a[473])|(b[473]))|((c[473])^(d[473])))|(e[473]); + assign q[474] = (a[474])^(!b[474]); + assign q[475] = (a[475])&(!b[475]); + assign q[476] = (((a[476])^(!b[476]))&((c[476])&(d[476])))|(!e[476]); + assign q[477] = ((a[477])^(b[477]))&(!c[477]); + assign q[478] = (((a[478])|(!b[478]))&((c[478])^(d[478])))|(e[478]); + assign q[479] = (((a[479])|(!b[479]))&((c[479])&(!d[479])))|(!e[479]); + assign q[480] = (((!a[480])|(b[480]))&((!c[480])|(!d[480])))|(e[480]); + assign q[481] = (((!a[481])&(b[481]))|((!c[481])^(d[481])))&(!e[481]); + assign q[482] = (a[482])^(!b[482]); + assign q[483] = (a[483])|(b[483]); + assign q[484] = (((a[484])|(!b[484]))&(c[484]))|(!d[484]); + assign q[485] = (((a[485])^(!b[485]))&(c[485]))|(!d[485]); + assign q[486] = ((!a[486])^(b[486]))&(c[486]); + assign q[487] = ((!a[487])&(b[487]))^((!c[487])^(!d[487])); + assign q[488] = ((a[488])&(b[488]))^((c[488])^(d[488])); + assign q[489] = (a[489])^(!b[489]); + assign q[490] = (((!a[490])^(b[490]))&(!c[490]))|(!d[490]); + assign q[491] = (a[491])^(!b[491]); + assign q[492] = (!a[492])|(!b[492]); + assign q[493] = (((!a[493])|(!b[493]))|((c[493])^(d[493])))^(e[493]); + assign q[494] = (((a[494])&(b[494]))^((c[494])&(!d[494])))&(e[494]); + assign q[495] = (((a[495])|(!b[495]))|((!c[495])^(d[495])))^(!e[495]); + assign q[496] = (((a[496])^(b[496]))&((!c[496])^(!d[496])))&(!e[496]); + assign q[497] = (((a[497])^(!b[497]))|((!c[497])&(d[497])))|(e[497]); + assign q[498] = (((!a[498])|(!b[498]))&(c[498]))&(!d[498]); + assign q[499] = (((a[499])|(b[499]))^((c[499])^(!d[499])))|(!e[499]); + assign q[500] = ((a[500])&(b[500]))^((!c[500])^(!d[500])); + assign q[501] = (((a[501])&(!b[501]))|(!c[501]))|(!d[501]); + assign q[502] = (((a[502])^(!b[502]))^(!c[502]))|(!d[502]); + assign q[503] = (((!a[503])&(b[503]))|(!c[503]))^(!d[503]); + assign q[504] = (((a[504])&(b[504]))|(c[504]))|(d[504]); + assign q[505] = (((!a[505])&(b[505]))&((c[505])&(!d[505])))^(!e[505]); + assign q[506] = (((!a[506])|(b[506]))|(c[506]))&(!d[506]); + assign q[507] = (((!a[507])^(b[507]))^(c[507]))&(d[507]); + assign q[508] = (((!a[508])&(b[508]))|((!c[508])|(d[508])))|(!e[508]); + assign q[509] = (!a[509])|(b[509]); + assign q[510] = (((a[510])|(!b[510]))^(c[510]))^(d[510]); + assign q[511] = ((!a[511])|(!b[511]))|((c[511])|(d[511])); + assign q[512] = ((a[512])|(!b[512]))&((!c[512])&(d[512])); + assign q[513] = (!a[513])&(!b[513]); + assign q[514] = (((a[514])|(!b[514]))^(!c[514]))&(d[514]); + assign q[515] = (((!a[515])|(!b[515]))^(c[515]))|(!d[515]); + assign q[516] = ((a[516])|(b[516]))|((c[516])&(!d[516])); + assign q[517] = (((a[517])^(!b[517]))^((c[517])&(!d[517])))&(e[517]); + assign q[518] = (((a[518])&(!b[518]))^((c[518])|(!d[518])))^(!e[518]); + assign q[519] = (((!a[519])^(!b[519]))&((c[519])&(d[519])))|(e[519]); + assign q[520] = ((a[520])^(b[520]))|((c[520])&(!d[520])); + assign q[521] = (((!a[521])^(!b[521]))^((!c[521])|(!d[521])))|(e[521]); + assign q[522] = (((a[522])|(b[522]))|(c[522]))&(!d[522]); + assign q[523] = (((a[523])|(b[523]))^((c[523])|(!d[523])))|(e[523]); + assign q[524] = ((!a[524])^(b[524]))&(c[524]); + assign q[525] = (a[525])&(b[525]); + assign q[526] = ((a[526])|(!b[526]))^((!c[526])^(!d[526])); + assign q[527] = ((!a[527])&(!b[527]))&((!c[527])|(!d[527])); + assign q[528] = ((a[528])^(b[528]))&(!c[528]); + assign q[529] = ((a[529])^(b[529]))|((c[529])|(!d[529])); + assign q[530] = ((!a[530])&(b[530]))|((c[530])&(!d[530])); + assign q[531] = (a[531])|(b[531]); + assign q[532] = (((!a[532])|(b[532]))&(c[532]))|(d[532]); + assign q[533] = ((a[533])&(!b[533]))&((c[533])&(!d[533])); + assign q[534] = (((a[534])&(!b[534]))&(!c[534]))|(d[534]); + assign q[535] = ((!a[535])^(b[535]))|((c[535])&(!d[535])); + assign q[536] = (((a[536])&(!b[536]))|((c[536])|(!d[536])))|(!e[536]); + assign q[537] = ((!a[537])^(b[537]))^((c[537])&(!d[537])); + assign q[538] = (((!a[538])&(b[538]))&(c[538]))|(d[538]); + assign q[539] = (a[539])|(!b[539]); + assign q[540] = (((!a[540])|(!b[540]))^((!c[540])|(d[540])))&(!e[540]); + assign q[541] = ((!a[541])&(!b[541]))&((c[541])^(d[541])); + assign q[542] = (((a[542])|(!b[542]))^(!c[542]))&(d[542]); + assign q[543] = (((!a[543])&(b[543]))&(!c[543]))^(d[543]); + assign q[544] = (((!a[544])|(b[544]))&((!c[544])&(d[544])))&(e[544]); + assign q[545] = (((a[545])^(!b[545]))|(!c[545]))&(d[545]); + assign q[546] = (((!a[546])|(!b[546]))^((!c[546])|(d[546])))&(!e[546]); + assign q[547] = (((a[547])^(!b[547]))|(c[547]))|(!d[547]); + assign q[548] = (((!a[548])^(b[548]))&((c[548])|(!d[548])))&(!e[548]); + assign q[549] = ((a[549])|(!b[549]))^((!c[549])^(d[549])); + assign q[550] = ((!a[550])&(!b[550]))^(c[550]); + assign q[551] = (((!a[551])&(b[551]))|((c[551])&(!d[551])))&(!e[551]); + assign q[552] = (((a[552])|(b[552]))^((!c[552])|(!d[552])))&(!e[552]); + assign q[553] = (((a[553])|(b[553]))|((!c[553])|(d[553])))&(e[553]); + assign q[554] = (((a[554])&(!b[554]))^(!c[554]))^(d[554]); + assign q[555] = ((!a[555])^(b[555]))|(!c[555]); + assign q[556] = (((!a[556])^(!b[556]))^(!c[556]))|(d[556]); + assign q[557] = ((a[557])&(!b[557]))|((c[557])&(d[557])); + assign q[558] = (((a[558])&(!b[558]))^((!c[558])^(!d[558])))^(!e[558]); + assign q[559] = (((!a[559])|(!b[559]))|((!c[559])|(!d[559])))^(!e[559]); + assign q[560] = ((!a[560])|(!b[560]))|((!c[560])^(d[560])); + assign q[561] = (((!a[561])|(b[561]))|(c[561]))^(!d[561]); + assign q[562] = ((!a[562])&(!b[562]))&((!c[562])^(!d[562])); + assign q[563] = (((a[563])^(b[563]))^(!c[563]))|(d[563]); + assign q[564] = (((!a[564])|(b[564]))|(!c[564]))|(d[564]); + assign q[565] = (((a[565])&(!b[565]))&((c[565])|(d[565])))|(!e[565]); + assign q[566] = (((a[566])&(b[566]))^(!c[566]))|(!d[566]); + assign q[567] = (((!a[567])&(!b[567]))&((c[567])&(!d[567])))|(!e[567]); + assign q[568] = (((!a[568])|(!b[568]))|(!c[568]))&(!d[568]); + assign q[569] = (!a[569])&(b[569]); + assign q[570] = ((!a[570])|(b[570]))|((!c[570])|(!d[570])); + assign q[571] = (((a[571])|(b[571]))&((!c[571])|(!d[571])))&(!e[571]); + assign q[572] = ((!a[572])&(b[572]))|((c[572])|(!d[572])); + assign q[573] = ((a[573])^(!b[573]))|((!c[573])|(!d[573])); + assign q[574] = (((!a[574])|(b[574]))&((!c[574])&(!d[574])))&(!e[574]); + assign q[575] = (((!a[575])&(b[575]))&((!c[575])|(!d[575])))|(!e[575]); + assign q[576] = (((a[576])|(!b[576]))^((c[576])^(d[576])))|(e[576]); + assign q[577] = (((a[577])|(b[577]))&(c[577]))^(d[577]); + assign q[578] = ((a[578])^(!b[578]))&(!c[578]); + assign q[579] = (((!a[579])&(!b[579]))^((!c[579])|(!d[579])))|(!e[579]); + assign q[580] = (((!a[580])|(b[580]))|(!c[580]))^(d[580]); + assign q[581] = ((a[581])&(b[581]))&((!c[581])|(d[581])); + assign q[582] = (((!a[582])^(b[582]))|(!c[582]))&(!d[582]); + assign q[583] = (a[583])&(b[583]); + assign q[584] = (((!a[584])|(b[584]))|((c[584])^(d[584])))^(e[584]); + assign q[585] = ((a[585])&(b[585]))|((!c[585])|(!d[585])); + assign q[586] = (((a[586])|(b[586]))^((!c[586])|(d[586])))^(!e[586]); + assign q[587] = ((a[587])|(!b[587]))&(!c[587]); + assign q[588] = (((!a[588])&(b[588]))^((!c[588])|(!d[588])))|(!e[588]); + assign q[589] = (((!a[589])|(b[589]))&((!c[589])|(d[589])))&(e[589]); + assign q[590] = (((a[590])^(b[590]))^((!c[590])&(d[590])))&(!e[590]); + assign q[591] = ((a[591])^(!b[591]))|(!c[591]); + assign q[592] = ((a[592])|(!b[592]))^((!c[592])^(!d[592])); + assign q[593] = ((!a[593])|(b[593]))&((c[593])&(!d[593])); + assign q[594] = ((!a[594])&(!b[594]))^(!c[594]); + assign q[595] = (((!a[595])^(b[595]))|(!c[595]))&(d[595]); + assign q[596] = (((a[596])|(!b[596]))&(!c[596]))|(!d[596]); + assign q[597] = (a[597])&(!b[597]); + assign q[598] = ((a[598])^(b[598]))|((!c[598])&(d[598])); + assign q[599] = ((a[599])&(b[599]))&(!c[599]); + assign q[600] = ((!a[600])|(b[600]))|((!c[600])^(!d[600])); + assign q[601] = ((a[601])&(!b[601]))|((c[601])^(!d[601])); + assign q[602] = ((!a[602])&(!b[602]))^(!c[602]); + assign q[603] = ((a[603])&(!b[603]))^((c[603])&(!d[603])); + assign q[604] = ((a[604])&(!b[604]))&((c[604])^(!d[604])); + assign q[605] = (((!a[605])|(b[605]))&((c[605])|(d[605])))|(e[605]); + assign q[606] = (((a[606])|(!b[606]))|((!c[606])^(d[606])))&(e[606]); + assign q[607] = ((a[607])&(!b[607]))^(!c[607]); + assign q[608] = ((a[608])^(!b[608]))&(!c[608]); + assign q[609] = ((a[609])^(!b[609]))&((!c[609])&(d[609])); + assign q[610] = ((!a[610])&(!b[610]))&(c[610]); + assign q[611] = (((!a[611])|(b[611]))&(!c[611]))|(!d[611]); + assign q[612] = (((a[612])^(!b[612]))&((!c[612])|(d[612])))^(e[612]); + assign q[613] = (((!a[613])|(b[613]))^((c[613])&(!d[613])))|(!e[613]); + assign q[614] = (a[614])^(!b[614]); + assign q[615] = (((!a[615])^(b[615]))|(!c[615]))^(d[615]); + assign q[616] = ((!a[616])&(!b[616]))|((c[616])&(!d[616])); + assign q[617] = (((a[617])^(b[617]))|(c[617]))|(d[617]); + assign q[618] = (((!a[618])^(!b[618]))^((c[618])^(d[618])))^(e[618]); + assign q[619] = (((!a[619])|(!b[619]))|(c[619]))^(!d[619]); + assign q[620] = (!a[620])^(!b[620]); + assign q[621] = ((!a[621])&(!b[621]))&((!c[621])|(d[621])); + assign q[622] = (((a[622])^(b[622]))&((!c[622])|(!d[622])))|(!e[622]); + assign q[623] = (((a[623])&(!b[623]))^(c[623]))&(d[623]); + assign q[624] = (((a[624])&(b[624]))|(c[624]))^(!d[624]); + assign q[625] = (((!a[625])^(!b[625]))&((!c[625])|(d[625])))&(!e[625]); + assign q[626] = (((!a[626])&(!b[626]))^(!c[626]))|(!d[626]); + assign q[627] = ((!a[627])|(b[627]))|(c[627]); + assign q[628] = (((!a[628])&(!b[628]))^((!c[628])|(!d[628])))^(e[628]); + assign q[629] = ((a[629])&(!b[629]))|((c[629])^(d[629])); + assign q[630] = (((!a[630])|(b[630]))^((c[630])|(!d[630])))|(!e[630]); + assign q[631] = (((!a[631])&(b[631]))&(!c[631]))^(!d[631]); + assign q[632] = (((a[632])&(!b[632]))&(!c[632]))|(!d[632]); + assign q[633] = (((a[633])|(b[633]))^(c[633]))|(d[633]); + assign q[634] = (((a[634])&(b[634]))|((c[634])|(d[634])))&(e[634]); + assign q[635] = (((a[635])&(!b[635]))&((c[635])&(!d[635])))&(!e[635]); + assign q[636] = (((!a[636])|(b[636]))^((!c[636])^(d[636])))^(e[636]); + assign q[637] = (((a[637])&(b[637]))&((!c[637])&(d[637])))|(!e[637]); + assign q[638] = ((!a[638])|(!b[638]))&(!c[638]); + assign q[639] = (((a[639])|(!b[639]))&((c[639])|(d[639])))^(!e[639]); + assign q[640] = (!a[640])&(b[640]); + assign q[641] = ((!a[641])^(!b[641]))^((!c[641])^(d[641])); + assign q[642] = (((!a[642])^(!b[642]))&(c[642]))&(!d[642]); + assign q[643] = (!a[643])^(!b[643]); + assign q[644] = ((!a[644])|(!b[644]))|((!c[644])^(!d[644])); + assign q[645] = (((a[645])&(b[645]))^((c[645])&(!d[645])))|(e[645]); + assign q[646] = ((a[646])&(!b[646]))&(c[646]); + assign q[647] = ((a[647])&(!b[647]))^((!c[647])^(!d[647])); + assign q[648] = (((!a[648])|(b[648]))&((!c[648])&(d[648])))|(e[648]); + assign q[649] = ((!a[649])|(b[649]))|((c[649])&(!d[649])); + assign q[650] = (((!a[650])&(b[650]))^(c[650]))^(d[650]); + assign q[651] = ((a[651])|(b[651]))^(!c[651]); + assign q[652] = (((a[652])^(b[652]))&((c[652])|(d[652])))|(e[652]); + assign q[653] = (((!a[653])|(b[653]))^(c[653]))^(d[653]); + assign q[654] = (((a[654])^(!b[654]))^(!c[654]))^(d[654]); + assign q[655] = (((!a[655])|(b[655]))|((!c[655])&(d[655])))&(e[655]); + assign q[656] = (((a[656])^(b[656]))|((!c[656])^(!d[656])))^(!e[656]); + assign q[657] = ((a[657])&(!b[657]))&(c[657]); + assign q[658] = (((!a[658])|(b[658]))|((!c[658])^(!d[658])))|(e[658]); + assign q[659] = (((a[659])&(b[659]))&((c[659])|(!d[659])))^(e[659]); + assign q[660] = (((!a[660])&(!b[660]))|((!c[660])|(!d[660])))&(e[660]); + assign q[661] = ((a[661])&(!b[661]))^((!c[661])^(!d[661])); + assign q[662] = (((!a[662])|(!b[662]))|((c[662])|(!d[662])))^(!e[662]); + assign q[663] = (a[663])^(b[663]); + assign q[664] = ((!a[664])&(!b[664]))|((!c[664])&(!d[664])); + assign q[665] = (((a[665])|(b[665]))&((!c[665])&(!d[665])))^(e[665]); + assign q[666] = (((a[666])&(b[666]))|((c[666])|(d[666])))|(!e[666]); + assign q[667] = ((a[667])&(!b[667]))&(!c[667]); + assign q[668] = (((!a[668])&(b[668]))^(c[668]))|(d[668]); + assign q[669] = (((!a[669])^(b[669]))^((!c[669])^(!d[669])))&(e[669]); + assign q[670] = ((!a[670])|(b[670]))&((c[670])|(!d[670])); + assign q[671] = (((a[671])&(!b[671]))^(c[671]))^(!d[671]); + assign q[672] = (((a[672])^(b[672]))^((c[672])&(!d[672])))|(!e[672]); + assign q[673] = (((a[673])^(!b[673]))&((c[673])|(d[673])))|(!e[673]); + assign q[674] = ((!a[674])|(!b[674]))|((!c[674])^(d[674])); + assign q[675] = ((!a[675])^(b[675]))&((!c[675])|(!d[675])); + assign q[676] = (((!a[676])&(!b[676]))^((!c[676])&(d[676])))|(!e[676]); + assign q[677] = (((!a[677])&(!b[677]))^(c[677]))&(!d[677]); + assign q[678] = (((!a[678])|(!b[678]))&((c[678])^(!d[678])))&(e[678]); + assign q[679] = (!a[679])|(b[679]); + assign q[680] = (a[680])&(!b[680]); + assign q[681] = (((!a[681])|(b[681]))|((c[681])&(d[681])))|(!e[681]); + assign q[682] = ((a[682])&(!b[682]))^((!c[682])|(!d[682])); + assign q[683] = ((!a[683])&(!b[683]))|((!c[683])^(!d[683])); + assign q[684] = (!a[684])&(!b[684]); + assign q[685] = (((a[685])&(!b[685]))|((c[685])&(!d[685])))|(!e[685]); + assign q[686] = (a[686])^(!b[686]); + assign q[687] = (((!a[687])|(b[687]))&((!c[687])|(d[687])))^(e[687]); + assign q[688] = (((a[688])^(!b[688]))^((!c[688])&(!d[688])))&(!e[688]); + assign q[689] = (((!a[689])^(b[689]))^(c[689]))&(!d[689]); + assign q[690] = ((a[690])^(!b[690]))|((!c[690])|(!d[690])); + assign q[691] = (((!a[691])^(b[691]))&((!c[691])&(!d[691])))^(!e[691]); + assign q[692] = ((a[692])^(!b[692]))|((c[692])|(!d[692])); + assign q[693] = (((a[693])&(b[693]))&((!c[693])|(d[693])))^(e[693]); + assign q[694] = ((!a[694])^(!b[694]))^((c[694])^(!d[694])); + assign q[695] = ((a[695])&(b[695]))&((!c[695])|(!d[695])); + assign q[696] = ((a[696])|(b[696]))&((c[696])|(d[696])); + assign q[697] = (((!a[697])^(b[697]))|((c[697])^(!d[697])))|(e[697]); + assign q[698] = (((a[698])|(b[698]))|((!c[698])&(!d[698])))^(!e[698]); + assign q[699] = (((!a[699])|(!b[699]))&(c[699]))|(!d[699]); + assign q[700] = ((!a[700])&(b[700]))|((!c[700])|(d[700])); + assign q[701] = (((!a[701])|(b[701]))|((c[701])^(d[701])))&(e[701]); + assign q[702] = (((!a[702])&(b[702]))&(c[702]))&(!d[702]); + assign q[703] = ((!a[703])&(!b[703]))|((c[703])|(d[703])); + assign q[704] = (((a[704])^(b[704]))^((c[704])&(d[704])))|(!e[704]); + assign q[705] = ((a[705])^(!b[705]))^((!c[705])^(!d[705])); + assign q[706] = (((!a[706])^(b[706]))^((!c[706])&(!d[706])))&(e[706]); + assign q[707] = ((a[707])&(!b[707]))|((c[707])^(d[707])); + assign q[708] = (((a[708])^(b[708]))|(!c[708]))|(d[708]); + assign q[709] = (((!a[709])&(b[709]))^((!c[709])&(!d[709])))&(!e[709]); + assign q[710] = ((!a[710])^(!b[710]))^(c[710]); + assign q[711] = (!a[711])&(b[711]); + assign q[712] = ((a[712])^(b[712]))&((c[712])^(!d[712])); + assign q[713] = (((a[713])^(b[713]))|((!c[713])^(d[713])))|(!e[713]); + assign q[714] = (((a[714])|(b[714]))&((c[714])^(d[714])))^(!e[714]); + assign q[715] = ((a[715])|(b[715]))|((!c[715])^(d[715])); + assign q[716] = (((a[716])|(b[716]))^(c[716]))^(!d[716]); + assign q[717] = (((!a[717])|(!b[717]))^((!c[717])^(!d[717])))^(e[717]); + assign q[718] = (((a[718])^(!b[718]))&(!c[718]))^(d[718]); + assign q[719] = (((!a[719])^(!b[719]))&((!c[719])|(d[719])))&(!e[719]); + assign q[720] = ((!a[720])^(b[720]))|(c[720]); + assign q[721] = ((!a[721])&(!b[721]))|((c[721])&(d[721])); + assign q[722] = (((!a[722])|(!b[722]))&((!c[722])&(!d[722])))&(!e[722]); + assign q[723] = ((a[723])|(b[723]))&((c[723])|(d[723])); + assign q[724] = (((!a[724])|(b[724]))^((c[724])^(!d[724])))^(e[724]); + assign q[725] = (((!a[725])^(!b[725]))|(!c[725]))&(!d[725]); + assign q[726] = ((a[726])^(!b[726]))^(c[726]); + assign q[727] = ((!a[727])&(!b[727]))^(c[727]); + assign q[728] = ((!a[728])^(!b[728]))^(c[728]); + assign q[729] = ((!a[729])&(b[729]))&(!c[729]); + assign q[730] = (((a[730])|(!b[730]))&(!c[730]))&(!d[730]); + assign q[731] = ((!a[731])|(!b[731]))^(c[731]); + assign q[732] = ((!a[732])&(!b[732]))|(c[732]); + assign q[733] = ((!a[733])&(!b[733]))^(!c[733]); + assign q[734] = (((a[734])|(b[734]))|((!c[734])^(!d[734])))|(!e[734]); + assign q[735] = (a[735])^(b[735]); + assign q[736] = ((!a[736])|(b[736]))&(!c[736]); + assign q[737] = (((!a[737])|(b[737]))|(c[737]))&(!d[737]); + assign q[738] = (((a[738])^(b[738]))^((c[738])^(!d[738])))|(e[738]); + assign q[739] = (!a[739])^(b[739]); + assign q[740] = (((a[740])|(b[740]))^((!c[740])^(!d[740])))&(!e[740]); + assign q[741] = ((!a[741])&(b[741]))^((!c[741])^(!d[741])); + assign q[742] = (((a[742])|(b[742]))|(c[742]))|(d[742]); + assign q[743] = (((a[743])&(b[743]))&((c[743])&(d[743])))|(!e[743]); + assign q[744] = (((!a[744])&(!b[744]))^((!c[744])&(d[744])))^(e[744]); + assign q[745] = (((!a[745])&(b[745]))^((!c[745])|(!d[745])))^(e[745]); + assign q[746] = (((a[746])&(b[746]))^(!c[746]))&(!d[746]); + assign q[747] = (((!a[747])^(b[747]))^((!c[747])^(d[747])))|(e[747]); + assign q[748] = (((a[748])^(b[748]))|((c[748])^(d[748])))&(!e[748]); + assign q[749] = (((a[749])^(b[749]))|((c[749])|(!d[749])))|(e[749]); +endmodule diff --git a/tests/arch/gatemate/luttrees.ys b/tests/arch/gatemate/luttrees.ys new file mode 100644 index 000000000..545643226 --- /dev/null +++ b/tests/arch/gatemate/luttrees.ys @@ -0,0 +1,13 @@ + +read_verilog luttrees.v +design -save read + +hierarchy -top luttrees +proc +equiv_opt -async2sync -assert -map +/gatemate/cells_sim.v synth_gatemate -noiopad -luttree -nomx4 -nomx8 # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd luttrees # Constrain all select calls below inside the top module + +select -assert-count 750 t:CC_LUT2 t:CC_L2T4 t:CC_L2T5 %% +select -assert-none t:CC_LUT2 t:CC_L2T4 t:CC_L2T5 %% t:* %D + -- cgit v1.2.3 From d78d807a7fa1747b40da8bac9e278183cf86d3cc Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Mon, 27 Jun 2022 15:47:55 +0200 Subject: memory_map: -keepdc option for formal Use it when invoking memory_map -rom-only from write_{smt2,btor}. --- backends/btor/btor.cc | 2 +- backends/smt2/smt2.cc | 2 +- passes/memory/memory_map.cc | 17 ++++++++++++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index 7dec70545..2dc3b5954 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -1405,7 +1405,7 @@ struct BtorBackend : public Backend { log_header(design, "Executing BTOR backend.\n"); log_push(); - Pass::call(design, "memory_map -rom-only"); + Pass::call(design, "memory_map -rom-only -keepdc"); Pass::call(design, "bmuxmap"); Pass::call(design, "demuxmap"); log_pop(); diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index 6e70f9043..c75d4a98a 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -1609,7 +1609,7 @@ struct Smt2Backend : public Backend { log_header(design, "Executing SMT2 backend.\n"); log_push(); - Pass::call(design, "memory_map -rom-only"); + Pass::call(design, "memory_map -rom-only -keepdc"); Pass::call(design, "bmuxmap"); Pass::call(design, "demuxmap"); log_pop(); diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index ccfb8c94f..5ec717733 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -31,6 +31,7 @@ struct MemoryMapWorker { bool attr_icase = false; bool rom_only = false; + bool keepdc = false; dict> attributes; RTLIL::Design *design; @@ -190,14 +191,15 @@ struct MemoryMapWorker { int addr = i + mem.start_offset; int idx = addr & ((1 << abits) - 1); + SigSpec w_init = init_data.extract(i*mem.width, mem.width); if (static_cells_map.count(addr) > 0) { data_reg_out[idx] = static_cells_map[addr]; count_static++; } - else if (mem.wr_ports.empty()) + else if (mem.wr_ports.empty() && (!keepdc || w_init.is_fully_def())) { - data_reg_out[idx] = init_data.extract(i*mem.width, mem.width); + data_reg_out[idx] = w_init; } else { @@ -220,7 +222,6 @@ struct MemoryMapWorker w_out_name = genid(mem.memid, "", addr, "$q"); RTLIL::Wire *w_out = module->addWire(w_out_name, mem.width); - SigSpec w_init = init_data.extract(i*mem.width, mem.width); if (!w_init.is_fully_undef()) w_out->attributes[ID::init] = w_init.as_const(); @@ -380,11 +381,15 @@ struct MemoryMapPass : public Pass { log(" -rom-only\n"); log(" only perform conversion for ROMs (memories with no write ports).\n"); log("\n"); + log(" -keepdc\n"); + log(" when mapping ROMs, keep x-bits shared across read ports.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { bool attr_icase = false; bool rom_only = false; + bool keepdc = false; dict> attributes; log_header(design, "Executing MEMORY_MAP pass (converting memories to logic and flip-flops).\n"); @@ -426,6 +431,11 @@ struct MemoryMapPass : public Pass { rom_only = true; continue; } + if (args[argidx] == "-keepdc") + { + keepdc = true; + continue; + } break; } extra_args(args, argidx, design); @@ -435,6 +445,7 @@ struct MemoryMapPass : public Pass { worker.attr_icase = attr_icase; worker.attributes = attributes; worker.rom_only = rom_only; + worker.keepdc = keepdc; worker.run(); } } -- cgit v1.2.3 From 869e6a1b6d463ff1e72e8ae57cae751be4000687 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 28 Jun 2022 00:19:25 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3c659b9aa..a8254e7fa 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.18+29 +YOSYS_VER := 0.18+33 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From a6b440b5c9c4fb0472c01aec84961c3f1b40c954 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 28 Jun 2022 19:05:35 +0200 Subject: memory_map: avoid undriven unused FF inputs for -keepdc --- passes/memory/memory_map.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index 5ec717733..fd5b1f1ad 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -228,6 +228,9 @@ struct MemoryMapWorker data_reg_out[idx] = w_out; c->setPort(ID::Q, w_out); + + if (mem.wr_ports.empty()) + module->connect(RTLIL::SigSig(w_in, w_out)); } } -- cgit v1.2.3 From a47254bd106b0cce210bd0ce282d84b44ceb07f1 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Wed, 29 Jun 2022 15:35:28 +0200 Subject: opt_dff: With -keepdc, never turn undef init vals into const drivers --- passes/opt/opt_dff.cc | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index 0ad4acec2..6ff2d1b4b 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -491,12 +491,17 @@ struct OptDffWorker ff.has_srst = false; ff.sig_d = ff.val_srst; changed = true; - } else { + } else if (!opt.keepdc || ff.val_init.is_fully_def()) { log("Handling never-active EN on %s (%s) from module %s (removing D path).\n", log_id(cell), log_id(cell->type), log_id(module)); // The D input path is effectively useless, so remove it (this will be a D latch, SR latch, or a const driver). ff.has_ce = ff.has_clk = ff.has_srst = false; changed = true; + } else { + // We need to keep the undefined initival around as such + ff.sig_d = ff.sig_q; + ff.has_ce = ff.has_srst = false; + changed = true; } } else if (ff.sig_ce == (ff.pol_ce ? State::S1 : State::S0)) { // Always-active enable. Just remove it. @@ -508,13 +513,20 @@ struct OptDffWorker } } - if (ff.has_clk) { - if (ff.sig_clk.is_fully_const()) { + if (ff.has_clk && ff.sig_clk.is_fully_const()) { + if (!opt.keepdc || ff.val_init.is_fully_def()) { // Const clock — the D input path is effectively useless, so remove it (this will be a D latch, SR latch, or a const driver). log("Handling const CLK on %s (%s) from module %s (removing D path).\n", log_id(cell), log_id(cell->type), log_id(module)); ff.has_ce = ff.has_clk = ff.has_srst = false; changed = true; + } else { + // Const clock, but we need to keep the undefined initval around as such + if (ff.has_ce || ff.has_srst || ff.sig_d != ff.sig_q) { + ff.sig_d = ff.sig_q; + ff.has_ce = ff.has_srst = false; + changed = true; + } } } @@ -550,7 +562,7 @@ struct OptDffWorker ff.has_srst = false; ff.sig_d = ff.val_srst; changed = true; - } else { + } else if (!opt.keepdc || ff.val_init.is_fully_def()) { // The D input path is effectively useless, so remove it (this will be a const-input D latch, SR latch, or a const driver). log("Handling D = Q on %s (%s) from module %s (removing D path).\n", log_id(cell), log_id(cell->type), log_id(module)); @@ -567,7 +579,7 @@ struct OptDffWorker } // The cell has been simplified as much as possible already. Now try to spice it up with enables / sync resets. - if (ff.has_clk) { + if (ff.has_clk && ff.sig_d != ff.sig_q) { if (!ff.has_arst && !ff.has_sr && (!ff.has_srst || !ff.has_ce || ff.ce_over_srst) && !opt.nosdff) { // Try to merge sync resets. std::map> groups; -- cgit v1.2.3 From 930bcf0e75f3b8d6c5afbdffda5ef7fd7eddc964 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Wed, 29 Jun 2022 18:28:34 +0200 Subject: smt2, btor: Revert calling memory_map -rom-only This approach had major issues with ROMs whose initialization was not fully defined. If required, memory_map -rom-only -keepdc should be called early in a formal flow instead. (This does require a careful choice of optimization passes though. Sby's scripts will be updated accordingly.) --- backends/btor/btor.cc | 1 - backends/smt2/smt2.cc | 1 - 2 files changed, 2 deletions(-) diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index 2dc3b5954..831a3ada2 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -1405,7 +1405,6 @@ struct BtorBackend : public Backend { log_header(design, "Executing BTOR backend.\n"); log_push(); - Pass::call(design, "memory_map -rom-only -keepdc"); Pass::call(design, "bmuxmap"); Pass::call(design, "demuxmap"); log_pop(); diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index c75d4a98a..7481e0510 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -1609,7 +1609,6 @@ struct Smt2Backend : public Backend { log_header(design, "Executing SMT2 backend.\n"); log_push(); - Pass::call(design, "memory_map -rom-only -keepdc"); Pass::call(design, "bmuxmap"); Pass::call(design, "demuxmap"); log_pop(); -- cgit v1.2.3 From 9d63a90e0e0f3e9bd86884eb4fe3262ce70ce819 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 30 Jun 2022 00:17:25 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a8254e7fa..398844357 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.18+33 +YOSYS_VER := 0.18+38 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From b80976b543fc9f19d8ac5e574b904f1f8c67cd49 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 30 Jun 2022 11:19:01 +0200 Subject: Update to new verific extensions inteface --- frontends/verific/verific.cc | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index bbf860c96..8ecf54472 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -57,7 +57,7 @@ USING_YOSYS_NAMESPACE #include "FileSystem.h" #ifdef YOSYSHQ_VERIFIC_EXTENSIONS -#include "InitialAssertions.h" +#include "VerificExtensions.h" #endif #ifndef YOSYSHQ_VERIFIC_API_VERSION @@ -2246,7 +2246,7 @@ void verific_import(Design *design, const std::map &par verific_params.Insert(i.first.c_str(), i.second.c_str()); #ifdef YOSYSHQ_VERIFIC_EXTENSIONS - InitialAssertions::Rewrite("work", &verific_params); + VerificExtensions::ElaborateAndRewrite("work", &verific_params); #endif if (top.empty()) { @@ -2312,6 +2312,9 @@ void verific_import(Design *design, const std::map &par nl_todo.erase(it); } +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + VerificExtensions::Reset(); +#endif hier_tree::DeleteHierarchicalTree(); veri_file::Reset(); #ifdef VERIFIC_VHDL_SUPPORT @@ -2493,6 +2496,8 @@ struct VerificPass : public Pass { log("\n"); log(" -v, -vv\n"); log(" Verbose log messages. (-vv is even more verbose than -v.)\n"); + log(" -pp \n"); + log(" Pretty print design after elaboration to specified file.\n"); log("\n"); log("The following additional import options are useful for debugging the Verific\n"); log("bindings (for Yosys and/or Verific developers):\n"); @@ -2539,6 +2544,9 @@ struct VerificPass : public Pass { log("Get/set Verific runtime flags.\n"); log("\n"); log("\n"); +#if defined(YOSYS_ENABLE_VERIFIC) and defined(YOSYSHQ_VERIFIC_EXTENSIONS) + VerificExtensions::Help(); +#endif log("Use YosysHQ Tabby CAD Suite if you need Yosys+Verific.\n"); log("https://www.yosyshq.com/\n"); log("\n"); @@ -2922,6 +2930,7 @@ struct VerificPass : public Pass { bool mode_autocover = false, mode_fullinit = false; bool flatten = false, extnets = false; string dumpfile; + string ppfile; Map parameters(STRING_HASH); for (argidx++; argidx < GetSize(args); argidx++) { @@ -2990,6 +2999,10 @@ struct VerificPass : public Pass { dumpfile = args[++argidx]; continue; } + if (args[argidx] == "-pp" && argidx+1 < GetSize(args)) { + ppfile = args[++argidx]; + continue; + } break; } @@ -2999,8 +3012,11 @@ struct VerificPass : public Pass { std::set top_mod_names; #ifdef YOSYSHQ_VERIFIC_EXTENSIONS - InitialAssertions::Rewrite(work, ¶meters); + VerificExtensions::ElaborateAndRewrite(work, ¶meters); #endif + if (!ppfile.empty()) + veri_file::PrettyPrint(ppfile.c_str(), nullptr, work.c_str()); + if (mode_all) { log("Running hier_tree::ElaborateAll().\n"); @@ -3113,6 +3129,9 @@ struct VerificPass : public Pass { nl_todo.erase(it); } +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + VerificExtensions::Reset(); +#endif hier_tree::DeleteHierarchicalTree(); veri_file::Reset(); #ifdef VERIFIC_VHDL_SUPPORT @@ -3187,6 +3206,13 @@ struct VerificPass : public Pass { } } } +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + if (VerificExtensions::Execute(args, argidx, work, + [this](const std::vector &args, size_t argidx, std::string msg) + { cmd_error(args, argidx, msg); } )) { + goto check_error; + } +#endif cmd_error(args, argidx, "Missing or unsupported mode parameter.\n"); -- cgit v1.2.3 From 5db542742b8f69405417e5a715b4b72ce4c78534 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Wed, 29 Jun 2022 17:53:58 +0200 Subject: async2sync: turn FFs with const clks into gclk FFs with feedback The formal backends do not support multiple clocks. This includes constant clocks. Constant clocks do appear in what isn't a proper multiclock design, for example when mapping not fully initialized ROMs. As converting FFs with constant clocks to FFs using the global is doable even in a single clock flow, make async2sync do this. --- passes/sat/async2sync.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/passes/sat/async2sync.cc b/passes/sat/async2sync.cc index 46c76eba9..6fdf470b1 100644 --- a/passes/sat/async2sync.cc +++ b/passes/sat/async2sync.cc @@ -75,6 +75,9 @@ struct Async2syncPass : public Pass { if (ff.has_gclk) continue; + if (ff.has_clk && ff.sig_clk.is_fully_const()) + ff.has_ce = ff.has_clk = ff.has_srst = false; + if (ff.has_clk) { if (ff.has_sr) { -- cgit v1.2.3 From 42721b6a129707e4cc8ce6f47533c2530077ba9d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 00:19:06 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 398844357..ed67f8b9b 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.18+38 +YOSYS_VER := 0.18+40 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From fda3a537e181419f3d6a807cb6847a56cc9f8319 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 1 Jul 2022 16:23:12 +0200 Subject: Update abc --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ed67f8b9b..f6dc4332b 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,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 = 09a7e6d +ABCREV = 1863430 ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 VERBOSE=$(Q) -- cgit v1.2.3 From c39bade1a75efd166e3db1d4c30ca1dbf8d39e1b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 2 Jul 2022 00:18:03 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f6dc4332b..074272b23 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.18+40 +YOSYS_VER := 0.18+48 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From de07eb11c196110cf7a3df4678f815751a874c05 Mon Sep 17 00:00:00 2001 From: Pepijn de Vos Date: Sun, 3 Jul 2022 12:45:03 +0200 Subject: Apicula now supports lutram --- techlibs/gowin/synth_gowin.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 15a0c41e0..0dffdf498 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -131,7 +131,6 @@ struct SynthGowinPass : public ScriptPass if (args[argidx] == "-json" && argidx+1 < args.size()) { json_file = args[++argidx]; nobram = true; - nolutram = true; continue; } if (args[argidx] == "-run" && argidx+1 < args.size()) { -- cgit v1.2.3 From 59b96bb1f82b6cf83e004488267e5576dbcfad4b Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 4 Jul 2022 11:09:06 +0200 Subject: Upadte documentation and changelog --- CHANGELOG | 15 ++++++++ frontends/verific/verific.cc | 1 + manual/command-reference-manual.tex | 76 +++++++++++++++---------------------- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e32d9d053..16c746957 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,21 @@ List of major changes and improvements between releases Yosys 0.18 .. Yosys 0.18-dev -------------------------- + * Various + - Added support for $pos cell in btor backend + + * New commands and options + - Added option "-rom-only" to "memory_libmap" pass + - Added option "-smtcheck" to "hierarchy" pass + - Added option "-keepdc" to "memory_libmap" pass + - Added option "-suffix" to "rename" pass + - Added "gatemate_foldinv" pass + + * GateMate support + - Added LUT tree mapping + + * Verific support + - Added option "-pp" to "verific -import" Yosys 0.17 .. Yosys 0.18 -------------------------- diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 8ecf54472..fd6208e86 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2496,6 +2496,7 @@ struct VerificPass : public Pass { log("\n"); log(" -v, -vv\n"); log(" Verbose log messages. (-vv is even more verbose than -v.)\n"); + log("\n"); log(" -pp \n"); log(" Pretty print design after elaboration to specified file.\n"); log("\n"); diff --git a/manual/command-reference-manual.tex b/manual/command-reference-manual.tex index 3a9259867..28b99f3a6 100644 --- a/manual/command-reference-manual.tex +++ b/manual/command-reference-manual.tex @@ -2256,6 +2256,16 @@ and simulus signal from FST file number of clock cycles to simulate (default: 20) \end{lstlisting} +\section{gatemate\_foldinv -- fold inverters into Gatemate LUT trees} +\label{cmd:gatemate_foldinv} +\begin{lstlisting}[numbers=left,frame=single] + gatemate_foldinv [selection] + + +This pass searches for $__CC_NOT cells and folds them into CC_LUT2, CC_L2T4 +and CC_L2T5 cells as created by LUT tree mapping. +\end{lstlisting} + \section{glift -- create GLIFT models and optimization problems} \label{cmd:glift} \begin{lstlisting}[numbers=left,frame=single] @@ -2950,6 +2960,12 @@ pass to word-wide DFFs and address decoders. -iattr for -attr, ignore case of . + + -rom-only + only perform conversion for ROMs (memories with no write ports). + + -keepdc + when mapping ROMs, keep x-bits shared across read ports. \end{lstlisting} \section{memory\_memx -- emulate vlog sim behavior for mem ports} @@ -4226,10 +4242,12 @@ Assign names auto-generated from the src attribute to all selected wires and cells with private names. - rename -wire [selection] + rename -wire [selection] [-suffix ] Assign auto-generated names based on the wires they drive to all selected cells with private names. Ignores cells driving privatly named wires. +By default, the cell is named after the wire with the cell type as suffix. +The -suffix option can be used to set the suffix to the given string instead. rename -enumerate [-pattern ] [selection] @@ -5988,6 +6006,9 @@ This command runs synthesis for Cologne Chip AG GateMate FPGAs. -nomx8, -nomx4 do not use CC_MX{8,4} multiplexer cells in output netlist. + -luttree + use new LUT tree mapping approach (EXPERIMENTAL). + -dff run 'abc' with -dff option @@ -6067,7 +6088,11 @@ The following commands are executed by this synthesis command: techmap -map +/gatemate/mux_map.v map_luts: - abc -dress -lut 4 + abc -genlib +/gatemate/lut_tree_cells.genlib (with -luttree) + techmap -map +/gatemate/lut_tree_map.v (with -luttree) + gatemate_foldinv (with -luttree) + techmap -map +/gatemate/inv_map.v (with -luttree) + abc -dress -lut 4 (without -luttree) clean map_cells: @@ -7901,6 +7926,9 @@ Import options: -v, -vv Verbose log messages. (-vv is even more verbose than -v.) + -pp + Pretty print design after elaboration to specified file. + The following additional import options are useful for debugging the Verific bindings (for Yosys and/or Verific developers): @@ -7941,50 +7969,6 @@ Pretty print options: Save output for VHDL design units. - verific -app .. - -Execute YosysHQ formal application on loaded Verilog files. - -Application options: - - -module - Run formal application only on specified module. - - -blacklist - Do not run application on modules from files that match the filename - or filename and line number if provided in such format. - Parameter can also contain comma separated list of file locations. - - -blfile - Do not run application on locations specified in file, they can - represent filename or filename and location in file. - -Applications: - - WARNING: Applications only available in commercial build. - - - verific -template .. - -Generate template for specified top module of loaded design. - -Template options: - - -out - Specifies output file for generated template, by default output is stdout - - -chparam name value - Generate template using this parameter value. Otherwise default parameter - values will be used for templat generate functionality. This option - can be specified multiple times to override multiple parameters. - String values must be passed in double quotes ("). - -Templates: - - WARNING: Templates only available in commercial build. - - - verific -cfg [ []] Get/set Verific runtime flags. -- cgit v1.2.3 From 5343911263ea10dc9d0fd308297314b4b42989d2 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Mon, 4 Jul 2022 13:54:49 +0200 Subject: Mention smtlib2_module in README.md and CHANGELOG --- CHANGELOG | 7 ++++--- README.md | 12 ++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 16c746957..97572c35d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,9 +4,6 @@ List of major changes and improvements between releases Yosys 0.18 .. Yosys 0.18-dev -------------------------- - * Various - - Added support for $pos cell in btor backend - * New commands and options - Added option "-rom-only" to "memory_libmap" pass - Added option "-smtcheck" to "hierarchy" pass @@ -14,6 +11,10 @@ Yosys 0.18 .. Yosys 0.18-dev - Added option "-suffix" to "rename" pass - Added "gatemate_foldinv" pass + * Formal Verification + - Added support for $pos cell in btor backend + - Added the "smtlib2_module" and "smtlib2_comb_expr" attributes + * GateMate support - Added LUT tree mapping diff --git a/README.md b/README.md index 0232a5ed0..f916b38ad 100644 --- a/README.md +++ b/README.md @@ -505,6 +505,18 @@ Verilog Attributes and non-standard features module. Modules with such cells will be reprocessed during the ``hierarchy`` pass once the referenced module definition(s) become available. +- The ``smtlib2_module`` attribute can be set on a blackbox module to specify a + formal model directly using SMT-LIB 2. For such a module, the + ``smtlib2_comb_expr`` attribute can be used on output ports to define their + value using an SMT-LIB 2 expression. For example: + + (* blackbox *) + (* smtlib2_module *) + module submod(a, b); + input [7:0] a; + (* smtlib2_comb_expr = "(bvnot a)" *) + output [7:0] b; + endmodule Non-standard or SystemVerilog features for formal verification ============================================================== -- cgit v1.2.3 From a45c131b37ce503e6de7783939eb38f89d9d64e7 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 4 Jul 2022 14:07:01 +0200 Subject: Release version 0.19 --- CHANGELOG | 2 +- Makefile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 97572c35d..8d1b76c78 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.18 .. Yosys 0.18-dev +Yosys 0.18 .. Yosys 0.19 -------------------------- * New commands and options - Added option "-rom-only" to "memory_libmap" pass diff --git a/Makefile b/Makefile index 074272b23..055e57cac 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.18+48 +YOSYS_VER := 0.19 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -145,7 +145,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 19ce3b4.. | wc -l`/;" Makefile +# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 19ce3b4.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # -- cgit v1.2.3 From da0682b99a48e41e606f7c0a769aaa8d770cad77 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 4 Jul 2022 14:08:53 +0200 Subject: Next dev cycle --- CHANGELOG | 3 +++ Makefile | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8d1b76c78..54c385cd8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,9 @@ List of major changes and improvements between releases ======================================================= +Yosys 0.19 .. Yosys 0.19-dev +-------------------------- + Yosys 0.18 .. Yosys 0.19 -------------------------- * New commands and options diff --git a/Makefile b/Makefile index 055e57cac..77896021b 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.19 +YOSYS_VER := 0.19+0 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -145,7 +145,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: -# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 19ce3b4.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline a45c131.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # -- cgit v1.2.3 From 0ca0932b5283a1bdd247a70ee179d64d425c4a44 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 4 Jul 2022 16:52:28 +0200 Subject: Update abc and build as C++ --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 77896021b..b666618c7 100644 --- a/Makefile +++ b/Makefile @@ -153,10 +153,10 @@ 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 = 1863430 +ABCREV = f159bef ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc -ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 VERBOSE=$(Q) +ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) # set ABCEXTERNAL = to use an external ABC instance # Note: The in-tree ABC (yosys-abc) will not be installed when ABCEXTERNAL is set. @@ -201,7 +201,7 @@ ifeq ($(CONFIG),clang) CXX = clang LD = clang++ CXXFLAGS += -std=$(CXXSTD) -Os -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H" +ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -Wno-c++11-narrowing" ifneq ($(SANITIZER),) $(info [Clang Sanitizer] $(SANITIZER)) @@ -260,7 +260,7 @@ else ifeq ($(CONFIG),emcc) CXX = emcc LD = emcc CXXFLAGS := -std=$(CXXSTD) $(filter-out -fPIC -ggdb,$(CXXFLAGS)) -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DABC_MEMALIGN=8" +ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DABC_MEMALIGN=8 -Wno-c++11-narrowing" EMCC_CXXFLAGS := -Os -Wno-warn-absolute-paths EMCC_LDFLAGS := --memory-init-file 0 --embed-file share EMCC_LDFLAGS += -s NO_EXIT_RUNTIME=1 -- cgit v1.2.3 From 4db820e9d48dde8b6da1a67b84dc31c8e47e8c93 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 4 Jul 2022 19:31:38 +0200 Subject: Fix static initialization, fixes mingw build --- techlibs/gatemate/gatemate_foldinv.cc | 41 ++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/techlibs/gatemate/gatemate_foldinv.cc b/techlibs/gatemate/gatemate_foldinv.cc index 20fbbf8a3..752f8aac0 100644 --- a/techlibs/gatemate/gatemate_foldinv.cc +++ b/techlibs/gatemate/gatemate_foldinv.cc @@ -34,26 +34,6 @@ struct LUTType { IdString output_param; }; -static const dict lut_types = { - {ID(CC_LUT2), {{ - {ID(I0), {0, ID(INIT)}}, - {ID(I1), {1, ID(INIT)}}, - }, ID(INIT)}}, - {ID(CC_L2T4), {{ - {ID(I0), {0, ID(INIT_L00)}}, - {ID(I1), {1, ID(INIT_L00)}}, - {ID(I2), {0, ID(INIT_L01)}}, - {ID(I3), {1, ID(INIT_L01)}}, - }, ID(INIT_L10)}}, - {ID(CC_L2T5), {{ - {ID(I0), {0, ID(INIT_L02)}}, - {ID(I1), {1, ID(INIT_L02)}}, - {ID(I2), {0, ID(INIT_L03)}}, - {ID(I3), {1, ID(INIT_L03)}}, - {ID(I4), {0, ID(INIT_L20)}}, - }, ID(INIT_L20)}}, -}; - struct FoldInvWorker { FoldInvWorker(Module *module) : module(module), sigmap(module) {}; Module *module; @@ -64,6 +44,27 @@ struct FoldInvWorker { // Mapping from inverter input to inverter dict inverter_input; + const dict lut_types = { + {ID(CC_LUT2), {{ + {ID(I0), {0, ID(INIT)}}, + {ID(I1), {1, ID(INIT)}}, + }, ID(INIT)}}, + {ID(CC_L2T4), {{ + {ID(I0), {0, ID(INIT_L00)}}, + {ID(I1), {1, ID(INIT_L00)}}, + {ID(I2), {0, ID(INIT_L01)}}, + {ID(I3), {1, ID(INIT_L01)}}, + }, ID(INIT_L10)}}, + {ID(CC_L2T5), {{ + {ID(I0), {0, ID(INIT_L02)}}, + {ID(I1), {1, ID(INIT_L02)}}, + {ID(I2), {0, ID(INIT_L03)}}, + {ID(I3), {1, ID(INIT_L03)}}, + {ID(I4), {0, ID(INIT_L20)}}, + }, ID(INIT_L20)}}, + }; + + void find_inverted_bits() { for (auto cell : module->selected_cells()) { -- cgit v1.2.3 From 086c2f322479a71f24a9b28bbdc258c895a98b5b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 00:16:20 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 77896021b..cf41ffa67 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.19+0 +YOSYS_VER := 0.19+2 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From 24b895778af0ce0cb872509be1d91229c3ba2bf6 Mon Sep 17 00:00:00 2001 From: Michael Nolan Date: Tue, 5 Jul 2022 15:15:54 -0400 Subject: Add support for GHDL modfloor operator --- backends/cxxrtl/cxxrtl.h | 21 +++++++++++++++++++++ backends/cxxrtl/cxxrtl_backend.cc | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/backends/cxxrtl/cxxrtl.h b/backends/cxxrtl/cxxrtl.h index b4ffa87cd..073921cc4 100644 --- a/backends/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/cxxrtl.h @@ -1575,6 +1575,27 @@ value mod_ss(const value &a, const value &b) { return divmod_ss(a, b).second; } +template +CXXRTL_ALWAYS_INLINE +value modfloor_uu(const value &a, const value &b) { + return divmod_uu(a, b).second; +} + +// GHDL Modfloor operator. Returns r=a mod b, such that r has the same sign as b and +// a=b*N+r where N is some integer +// In practical terms, when a and b have different signs and the remainder returned by divmod_ss is not 0 +// then return the remainder + b +template +CXXRTL_ALWAYS_INLINE +value modfloor_ss(const value &a, const value &b) { + value r; + r = divmod_ss(a, b).second; + if((b.is_neg() != a.is_neg()) && !r.is_zero()) + return add_ss(b, r); + return r; +} + + // Memory helper struct memory_index { bool valid; diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index 404755b1e..62768bd33 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -185,7 +185,7 @@ bool is_binary_cell(RTLIL::IdString type) ID($and), ID($or), ID($xor), ID($xnor), ID($logic_and), ID($logic_or), ID($shl), ID($sshl), ID($shr), ID($sshr), ID($shift), ID($shiftx), ID($eq), ID($ne), ID($eqx), ID($nex), ID($gt), ID($ge), ID($lt), ID($le), - ID($add), ID($sub), ID($mul), ID($div), ID($mod)); + ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($modfloor)); } bool is_extending_cell(RTLIL::IdString type) -- cgit v1.2.3 From 0098b32c6c36e304b577bbe09eff2d645035fadb Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 6 Jul 2022 10:53:35 +0200 Subject: using more portable formatting --- kernel/rtlil.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 7a0b6b9c7..ee918441e 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -168,7 +168,7 @@ namespace RTLIL log_assert(p[1] != 0); for (const char *c = p; *c; c++) if ((unsigned)*c <= (unsigned)' ') - log_error("Found control character or space (0x%02hhx) in string '%s' which is not allowed in RTLIL identifiers\n", *c, p); + log_error("Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\n", *c, p); #ifndef YOSYS_NO_IDS_REFCNT if (global_free_idx_list_.empty()) { -- cgit v1.2.3 From 09c6fc68c7538306f10794e6456c74815ec9e570 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 7 Jul 2022 00:19:32 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 534ee3f1d..debc9eccd 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.19+2 +YOSYS_VER := 0.19+10 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From 43d86f2c26e2950b1b08dd46a324582668bbcf57 Mon Sep 17 00:00:00 2001 From: Catherine Date: Thu, 7 Jul 2022 08:06:55 +0000 Subject: Fix WASI build after commit 0ca0932b5. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index debc9eccd..84937d2e7 100644 --- a/Makefile +++ b/Makefile @@ -314,7 +314,7 @@ CXXFLAGS := $(WASIFLAGS) -std=$(CXXSTD) -Os $(filter-out -fPIC,$(CXXFLAGS)) LDFLAGS := $(WASIFLAGS) -Wl,-z,stack-size=1048576 $(filter-out -rdynamic,$(LDFLAGS)) LDLIBS := $(filter-out -lrt,$(LDLIBS)) ABCMKARGS += AR="$(AR)" RANLIB="$(RANLIB)" -ABCMKARGS += ARCHFLAGS="$(WASIFLAGS) -DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING" +ABCMKARGS += ARCHFLAGS="$(WASIFLAGS) -DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING -Wno-c++11-narrowing" ABCMKARGS += OPTFLAGS="-Os" EXE = .wasm -- cgit v1.2.3 From 502b96fe53e82b5454fbbd032cbf6b13ad2dad6d Mon Sep 17 00:00:00 2001 From: Catherine Date: Thu, 7 Jul 2022 08:08:17 +0000 Subject: Fix external ABC build after commit 0ca0932b5. --- Makefile | 2 +- passes/techmap/abc.cc | 6 ++++-- passes/techmap/abc9_exe.cc | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 84937d2e7..1d026d3dc 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,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 = f159bef +ABCREV = 5f40c47 ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 61ee99ee7..0b9c327c0 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -65,7 +65,9 @@ #include "frontends/blif/blifparse.h" #ifdef YOSYS_LINK_ABC -extern "C" int Abc_RealMain(int argc, char *argv[]); +namespace abc { + int Abc_RealMain(int argc, char *argv[]); +} #endif USING_YOSYS_NAMESPACE @@ -1098,7 +1100,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin abc_argv[2] = strdup("-f"); abc_argv[3] = strdup(tmp_script_name.c_str()); abc_argv[4] = 0; - int ret = Abc_RealMain(4, abc_argv); + int ret = abc::Abc_RealMain(4, abc_argv); free(abc_argv[0]); free(abc_argv[1]); free(abc_argv[2]); diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc index a66e95e21..7dc0a364b 100644 --- a/passes/techmap/abc9_exe.cc +++ b/passes/techmap/abc9_exe.cc @@ -31,7 +31,9 @@ #endif #ifdef YOSYS_LINK_ABC -extern "C" int Abc_RealMain(int argc, char *argv[]); +namespace abc { + int Abc_RealMain(int argc, char *argv[]); +} #endif std::string fold_abc9_cmd(std::string str) @@ -277,7 +279,7 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe abc9_argv[2] = strdup("-f"); abc9_argv[3] = strdup(tmp_script_name.c_str()); abc9_argv[4] = 0; - int ret = Abc_RealMain(4, abc9_argv); + int ret = abc::Abc_RealMain(4, abc9_argv); free(abc9_argv[0]); free(abc9_argv[1]); free(abc9_argv[2]); -- cgit v1.2.3 From 2326b9f90a131a592a7ce966005bd147f1ae49b0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 8 Jul 2022 00:20:05 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1d026d3dc..e32434141 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.19+10 +YOSYS_VER := 0.19+14 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From 58c51b9a0bd63af7bfc11f7ba4d19c0e933c18ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Mon, 11 Jul 2022 16:19:34 +0200 Subject: Remove empty lines --- kernel/yosys.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 521717ce7..c532115d8 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -777,8 +777,6 @@ struct TclPass : public Pass { log("Note, tcl will not recieve the output of any yosys command. If the output\n"); log("of the tcl commands are needed, use the yosys command 'tee' to redirect yosys's\n"); log("output to a temporary file.\n"); - - log("\n"); } void execute(std::vector args, RTLIL::Design *) override { -- cgit v1.2.3 From 08c319fc352fb2670b7416b5fb16ddcb9a400049 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 12 Jul 2022 00:17:15 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e32434141..71be8ff17 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.19+14 +YOSYS_VER := 0.19+18 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From d25f349f4d7de06da49df90af91a5cbdd0ae3237 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 15 Jul 2022 12:51:03 +0200 Subject: Update to latest abc --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 71be8ff17..92416d1b0 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,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 = 5f40c47 +ABCREV = c95d949 ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) @@ -314,7 +314,7 @@ CXXFLAGS := $(WASIFLAGS) -std=$(CXXSTD) -Os $(filter-out -fPIC,$(CXXFLAGS)) LDFLAGS := $(WASIFLAGS) -Wl,-z,stack-size=1048576 $(filter-out -rdynamic,$(LDFLAGS)) LDLIBS := $(filter-out -lrt,$(LDLIBS)) ABCMKARGS += AR="$(AR)" RANLIB="$(RANLIB)" -ABCMKARGS += ARCHFLAGS="$(WASIFLAGS) -DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING -Wno-c++11-narrowing" +ABCMKARGS += ARCHFLAGS="$(WASIFLAGS) -DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING -DABC_NO_RLIMIT -Wno-c++11-narrowing" ABCMKARGS += OPTFLAGS="-Os" EXE = .wasm -- cgit v1.2.3 From a82eff2e2091b5f7fa4f2b530c85dde7f3dd0d94 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 16 Jul 2022 00:18:51 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 92416d1b0..731b2eab2 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.19+18 +YOSYS_VER := 0.19+20 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From 793b9ade56bbc06d9d03dc0522de4ea0cd656b4f Mon Sep 17 00:00:00 2001 From: Josuah Demangeon Date: Fri, 8 Jul 2022 12:40:26 +0200 Subject: extends the list of platforms without This permits to fix a compilation bug on OpenBSD https://www.gnu.org/software/gnulib/manual/html_node/alloca_002eh.html > This header file is missing on some platforms: > FreeBSD 6.0, NetBSD 9.0, OpenBSD 6.7, mingw, MSVC 14. --- libs/fst/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/fst/config.h b/libs/fst/config.h index cd036f16a..a2f0fca82 100644 --- a/libs/fst/config.h +++ b/libs/fst/config.h @@ -21,7 +21,7 @@ #undef HAVE_LIBPTHREAD #undef HAVE_FSEEKO #endif -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) #undef HAVE_ALLOCA_H #endif -- cgit v1.2.3 From 6eba56fcf0c8f5e7bddfdf2d71fd157c71876ae8 Mon Sep 17 00:00:00 2001 From: Josuah Demangeon Date: Fri, 8 Jul 2022 13:39:18 +0200 Subject: include changes to support OpenBSD and prepare NetBSD support Some systems do not split -lrt and -ldl from the main libc. Musl libc is one of them, but offers an empty -ldl and -lrt precisely to avoid these kind of compilation errors. OpenBSD tried to add a librt.a but it broke libtool-based packages on multiple OSes[1] so it got reverted, nad -lrt needs to be removed. Some other adjustments for FreeBSD also work for other BSD, like packages in /usr/local/ instead of /usr/, TLC libraries... [1]: https://marc.info/?l=openbsd-tech&m=139559970907629&w=2 --- Makefile | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 92416d1b0..65efc62a5 100644 --- a/Makefile +++ b/Makefile @@ -126,8 +126,10 @@ endif else LDFLAGS += -rdynamic +ifneq ($(OS), OpenBSD) LDLIBS += -lrt endif +endif YOSYS_VER := 0.19+18 @@ -395,7 +397,7 @@ endif # ENABLE_PYOSYS ifeq ($(ENABLE_READLINE),1) CXXFLAGS += -DYOSYS_ENABLE_READLINE -ifeq ($(OS), FreeBSD) +ifeq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD)) CXXFLAGS += -I/usr/local/include endif LDLIBS += -lreadline @@ -430,7 +432,7 @@ endif ifeq ($(ENABLE_PLUGINS),1) CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags libffi) -DYOSYS_ENABLE_PLUGINS LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi) -ifneq ($(OS), FreeBSD) +ifneq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD)) LDLIBS += -ldl endif endif @@ -447,7 +449,7 @@ endif ifeq ($(ENABLE_TCL),1) TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')") -ifeq ($(OS), FreeBSD) +ifeq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD)) TCL_INCLUDE ?= /usr/local/include/$(TCL_VERSION) else TCL_INCLUDE ?= /usr/include/$(TCL_VERSION) @@ -458,8 +460,8 @@ CXXFLAGS += -DYOSYS_ENABLE_TCL LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz -luserenv else CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL -ifeq ($(OS), FreeBSD) -# FreeBSD uses tcl8.6, but lib is named "libtcl86" +ifeq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD)) +# BSDs usually use tcl8.6, but the lib is named "libtcl86" LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo -l$(TCL_VERSION) | tr -d '.') else LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo -l$(TCL_VERSION)) -- cgit v1.2.3 From 58fddf61ccd4715150f1dba40e62eac650ef9ee3 Mon Sep 17 00:00:00 2001 From: Josuah Demangeon Date: Sat, 16 Jul 2022 00:47:00 +0200 Subject: reduce the Makefile TCL compatibility code --- Makefile | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 65efc62a5..99f7f8996 100644 --- a/Makefile +++ b/Makefile @@ -450,9 +450,12 @@ endif ifeq ($(ENABLE_TCL),1) TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')") ifeq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD)) +# BSDs usually use tcl8.6, but the lib is named "libtcl86" TCL_INCLUDE ?= /usr/local/include/$(TCL_VERSION) +TCL_LIBS ?= -l$(subst .,,$(TCL_VERSION)) else TCL_INCLUDE ?= /usr/include/$(TCL_VERSION) +TCL_LIBS ?= -l$(TCL_VERSION) endif ifeq ($(CONFIG),mxe) @@ -460,12 +463,7 @@ CXXFLAGS += -DYOSYS_ENABLE_TCL LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz -luserenv else CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL -ifeq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD)) -# BSDs usually use tcl8.6, but the lib is named "libtcl86" -LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo -l$(TCL_VERSION) | tr -d '.') -else -LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo -l$(TCL_VERSION)) -endif +LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo $(TCL_LIBS)) endif endif -- cgit v1.2.3 From 14ba50908bd53186b13845499635fb3f9ddc60c1 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Fri, 22 Jul 2022 14:47:00 +0200 Subject: sim: Fix $anyseq in nested modules --- passes/sat/sim.cc | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index d085fab2d..53644c6b7 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -157,6 +157,7 @@ struct SimInstance dict> signal_database; dict fst_handles; + dict fst_inputs; dict> fst_memories; SimInstance(SimShared *shared, std::string scope, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) : @@ -820,7 +821,7 @@ struct SimInstance return did_something; } - void addAdditionalInputs(std::map &inputs) + void addAdditionalInputs() { for (auto cell : module->cells()) { @@ -831,7 +832,7 @@ struct SimInstance for(auto &item : fst_handles) { if (item.second==0) continue; // Ignore signals not found if (sig_y == sigmap(item.first)) { - inputs[sig_y.as_wire()] = item.second; + fst_inputs[sig_y.as_wire()] = item.second; found = true; break; } @@ -842,7 +843,21 @@ struct SimInstance } } for (auto child : children) - child.second->addAdditionalInputs(inputs); + child.second->addAdditionalInputs(); + } + + bool setInputs() + { + bool did_something = false; + for(auto &item : fst_inputs) { + std::string v = shared->fst->valueOf(item.second); + did_something |= set_state(item.first, Const::from_string(v)); + } + + for (auto child : children) + did_something |= child.second->setInputs(); + + return did_something; } void setState(dict> bits, std::string values) @@ -1095,18 +1110,17 @@ struct SimWorker : SimShared } SigMap sigmap(topmod); - std::map inputs; for (auto wire : topmod->wires()) { if (wire->port_input) { fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name)); if (id==0) log_error("Unable to find required '%s' signal in file\n",(scope + "." + RTLIL::unescape_id(wire->name)).c_str()); - inputs[wire] = id; + top->fst_inputs[wire] = id; } } - top->addAdditionalInputs(inputs); + top->addAdditionalInputs(); uint64_t startCount = 0; uint64_t stopCount = 0; @@ -1152,11 +1166,7 @@ struct SimWorker : SimShared fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, [&](uint64_t time) { if (verbose) log("Co-simulating %s %d [%lu%s].\n", (all_samples ? "sample" : "cycle"), cycle, (unsigned long)time, fst->getTimescaleString()); - bool did_something = false; - for(auto &item : inputs) { - std::string v = fst->valueOf(item.second); - did_something |= top->set_state(item.first, Const::from_string(v)); - } + bool did_something = top->setInputs(); if (initial) { did_something |= top->setInitState(); -- cgit v1.2.3 From 7e02b6a70b824aeffcae493f99623126de6470ef Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 23 Jul 2022 00:18:40 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 731b2eab2..e0e552d54 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.19+20 +YOSYS_VER := 0.19+23 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From f679b756d8f9af44654132d3fd4e3a3465afea89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Sat, 23 Jul 2022 16:42:54 +0200 Subject: opt_reduce: Fix use-after-free. Fixes #3418. --- passes/opt/opt_reduce.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc index 1a7c93fbd..c36a38dae 100644 --- a/passes/opt/opt_reduce.cc +++ b/passes/opt/opt_reduce.cc @@ -594,11 +594,9 @@ struct OptReduceWorker if (cell->type.in(ID($mux), ID($pmux))) opt_pmux(cell); - - if (cell->type == ID($bmux)) + else if (cell->type == ID($bmux)) opt_bmux(cell); - - if (cell->type == ID($demux)) + else if (cell->type == ID($demux)) opt_demux(cell); } } -- cgit v1.2.3 From 358e656e21bbbf6f09bb9f353a3829123f73d3b6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 24 Jul 2022 00:21:02 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e0e552d54..e91073352 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.19+23 +YOSYS_VER := 0.19+25 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From bc012995b44ca9a68524ae3a1ecb4b871d1436c9 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 26 Jul 2022 17:26:13 +0200 Subject: Support using ABC source tarball distribution --- Makefile | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index d4c04be8d..b50919ad8 100644 --- a/Makefile +++ b/Makefile @@ -155,7 +155,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 = c95d949 +ABCREV = 4e89fc7 ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) @@ -772,11 +772,16 @@ ifneq ($(ABCREV),default) $(Q) if test -d abc/.hg; then \ echo 'REEBE: NOP qverpgbel vf n ut jbexvat pbcl! Erzbir nop/ naq er-eha "znxr".' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \ fi - $(Q) if test -d abc && ! git -C abc diff-index --quiet HEAD; then \ + $(Q) if test -d abc && test -d abc/.git && ! git -C abc diff-index --quiet HEAD; then \ echo 'REEBE: NOP pbagnvaf ybpny zbqvsvpngvbaf! Frg NOPERI=qrsnhyg va Lbflf Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \ fi + $(Q) if test -d abc && ! test -d abc/.git && ! test "`cat abc/.gitcommit | cut -c1-7`" == "$(ABCREV)"; then \ + echo 'REEBE: Qbjaybnqrq NOP irefvbaf qbrf abg zngpu! Qbjaybnq sebz:' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; echo $(ABCURL)/archive/$(ABCREV).tar.gz; false; \ + fi # set a variable so the test fails if git fails to run - when comparing outputs directly, empty string would match empty string - $(Q) if ! (cd abc 2> /dev/null && rev="`git rev-parse $(ABCREV)`" && test "`git rev-parse HEAD`" == "$$rev"); then \ + $(Q) if test -d abc && ! test -d abc/.git && test "`cat abc/.gitcommit | cut -c1-7`" == "$(ABCREV)"; then \ + echo "Compiling local copy of ABC"; \ + elif ! (cd abc 2> /dev/null && rev="`git rev-parse $(ABCREV)`" && test "`git rev-parse HEAD`" == "$$rev"); then \ test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \ echo "Pulling ABC from $(ABCURL):"; set -x; \ test -d abc || git clone $(ABCURL) abc; \ -- cgit v1.2.3 From 29a5947bf83c8011e62cc859a0a832ee8ab690ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miodrag=20Milanovi=C4=87?= Date: Wed, 27 Jul 2022 14:16:46 +0200 Subject: Make all compile under OpenBSD (#3423) Co-authored-by: Josuah Demangeon --- Makefile | 11 ++++++++--- kernel/driver.cc | 13 +++++++++++++ kernel/yosys.cc | 29 +++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index b50919ad8..067e0bbf0 100644 --- a/Makefile +++ b/Makefile @@ -155,7 +155,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 = 4e89fc7 +ABCREV = 7cc11f7 ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) @@ -199,11 +199,16 @@ endif endif +ABC_ARCHFLAGS = "" +ifeq ($(OS), OpenBSD) +ABC_ARCHFLAGS += "-DABC_NO_RLIMIT" +endif + ifeq ($(CONFIG),clang) CXX = clang LD = clang++ CXXFLAGS += -std=$(CXXSTD) -Os -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -Wno-c++11-narrowing" +ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -Wno-c++11-narrowing $(ABC_ARCHFLAGS)" ifneq ($(SANITIZER),) $(info [Clang Sanitizer] $(SANITIZER)) @@ -226,7 +231,7 @@ else ifeq ($(CONFIG),gcc) CXX = gcc LD = gcc CXXFLAGS += -std=$(CXXSTD) -Os -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H" +ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)" else ifeq ($(CONFIG),gcc-static) LD = $(CXX) diff --git a/kernel/driver.cc b/kernel/driver.cc index f8f940e89..e52e1fb0e 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -192,6 +192,13 @@ void yosys_atexit() #endif } +#if defined(__OpenBSD__) +namespace Yosys { +extern char *yosys_argv0; +extern char yosys_path[PATH_MAX]; +}; +#endif + int main(int argc, char **argv) { std::string frontend_command = "auto"; @@ -498,6 +505,12 @@ int main(int argc, char **argv) if (print_stats) log_hasher = new SHA1; +#if defined(__OpenBSD__) + // save the executable origin for proc_self_dirname() + yosys_argv0 = argv[0]; + realpath(yosys_argv0, yosys_path); +#endif + #if defined(__linux__) // set stack size to >= 128 MB { diff --git a/kernel/yosys.cc b/kernel/yosys.cc index c532115d8..11df235e4 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -871,6 +871,35 @@ std::string proc_self_dirname() { return "/"; } +#elif defined(__OpenBSD__) +char yosys_path[PATH_MAX]; +char *yosys_argv0; + +std::string proc_self_dirname(void) +{ + char buf[PATH_MAX + 1] = "", *path, *p; + // if case argv[0] contains a valid path, return it + if (strlen(yosys_path) > 0) { + p = strrchr(yosys_path, '/'); + snprintf(buf, sizeof buf, "%*s/", (int)(yosys_path - p), yosys_path); + return buf; + } + // if argv[0] does not, reconstruct the path out of $PATH + path = strdup(getenv("PATH")); + if (!path) + log_error("getenv(\"PATH\") failed: %s\n", strerror(errno)); + for (p = strtok(path, ":"); p; p = strtok(NULL, ":")) { + snprintf(buf, sizeof buf, "%s/%s", p, yosys_argv0); + if (access(buf, X_OK) == 0) { + *(strrchr(buf, '/') + 1) = '\0'; + free(path); + return buf; + } + } + free(path); + log_error("Can't determine yosys executable path\n."); + return NULL; +} #else #error "Don't know how to determine process executable base path!" #endif -- cgit v1.2.3 From 6ba48515b5d0bf9568bb1312e23ea596acd7a501 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 27 Jul 2022 15:02:01 +0200 Subject: macos 10.15 deprecated by gh actions --- .github/workflows/test-macos.yml | 54 ---------------------------------------- 1 file changed, 54 deletions(-) diff --git a/.github/workflows/test-macos.yml b/.github/workflows/test-macos.yml index b14ce8633..22cf5e658 100644 --- a/.github/workflows/test-macos.yml +++ b/.github/workflows/test-macos.yml @@ -71,57 +71,3 @@ jobs: shell: bash run: | make -j${{ env.procs }} test CXXSTD=${{ matrix.cpp_std }} CC=cc CXX=cc LD=cc - - - test-macos-homebrew: - runs-on: ${{ matrix.os.id }} - strategy: - matrix: - os: - - { id: macos-10.15, name: Catalina } - cpp_std: - - 'c++17' - compiler: - - gcc - fail-fast: false - steps: - - name: Install Dependencies - run: | - brew install bison flex gawk libffi pkg-config bash - - - name: Runtime environment - shell: bash - env: - WORKSPACE: ${{ github.workspace }} - run: | - echo "GITHUB_WORKSPACE=`pwd`" >> $GITHUB_ENV - echo "$GITHUB_WORKSPACE/.local/bin" >> $GITHUB_PATH - echo "$(brew --prefix bison)/bin" >> $GITHUB_PATH - echo "$(brew --prefix flex)/bin" >> $GITHUB_PATH - echo "procs=$(sysctl -n hw.ncpu)" >> $GITHUB_ENV - - - name: Setup compiler - shell: bash - run: | - brew install ${{ matrix.compiler }} - CC=${COMPILER/@/-} - CXX=${CC/#gcc/g++} - echo "CC=$CC" >> $GITHUB_ENV - echo "CXX=$CXX" >> $GITHUB_ENV - env: - COMPILER: ${{ matrix.compiler }} - - - name: Tool versions - shell: bash - run: | - $CC --version - $CXX --version - - - name: Checkout Yosys - uses: actions/checkout@v2 - - - name: Build yosys - shell: bash - run: | - make config-gcc - make -j${{ env.procs }} CXXSTD=${{ matrix.cpp_std }} CC=$CC CXX=$CC LD=$CC -- cgit v1.2.3 From a6819042378d6b211f2e9c5a24fafb01fbde2bec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Wed, 27 Jul 2022 16:15:11 +0200 Subject: Assorted microoptimization speedups in core data structures. --- kernel/log.cc | 2 +- kernel/log.h | 2 +- kernel/rtlil.cc | 181 +++++++++++++++++++------------------------------------- kernel/rtlil.h | 118 +++++++++++++++++------------------- kernel/yosys.cc | 5 -- kernel/yosys.h | 2 +- 6 files changed, 117 insertions(+), 193 deletions(-) diff --git a/kernel/log.cc b/kernel/log.cc index 4bcce3b28..4403dd0c7 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -627,7 +627,7 @@ const char *log_const(const RTLIL::Const &value, bool autoint) } } -const char *log_id(RTLIL::IdString str) +const char *log_id(const RTLIL::IdString &str) { log_id_cache.push_back(strdup(str.c_str())); const char *p = log_id_cache.back(); diff --git a/kernel/log.h b/kernel/log.h index ea14028dd..3bc9fd978 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -237,7 +237,7 @@ void log_check_expected(); const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true); const char *log_const(const RTLIL::Const &value, bool autoint = true); -const char *log_id(RTLIL::IdString id); +const char *log_id(const RTLIL::IdString &id); template static inline const char *log_id(T *obj, const char *nullstr = nullptr) { if (nullstr && obj == nullptr) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index dc4ea9a78..b274bba78 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -199,11 +199,6 @@ const pool &RTLIL::builtin_ff_cell_types() { return res; } -RTLIL::Const::Const() -{ - flags = RTLIL::CONST_FLAG_NONE; -} - RTLIL::Const::Const(const std::string &str) { flags = RTLIL::CONST_FLAG_STRING; @@ -395,12 +390,12 @@ bool RTLIL::Const::is_onehot(int *pos) const return found; } -bool RTLIL::AttrObject::has_attribute(RTLIL::IdString id) const +bool RTLIL::AttrObject::has_attribute(const RTLIL::IdString &id) const { return attributes.count(id); } -void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value) +void RTLIL::AttrObject::set_bool_attribute(const RTLIL::IdString &id, bool value) { if (value) attributes[id] = RTLIL::Const(1); @@ -408,7 +403,7 @@ void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value) attributes.erase(id); } -bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const +bool RTLIL::AttrObject::get_bool_attribute(const RTLIL::IdString &id) const { const auto it = attributes.find(id); if (it == attributes.end()) @@ -416,7 +411,7 @@ bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const return it->second.as_bool(); } -void RTLIL::AttrObject::set_string_attribute(RTLIL::IdString id, string value) +void RTLIL::AttrObject::set_string_attribute(const RTLIL::IdString& id, string value) { if (value.empty()) attributes.erase(id); @@ -424,7 +419,7 @@ void RTLIL::AttrObject::set_string_attribute(RTLIL::IdString id, string value) attributes[id] = value; } -string RTLIL::AttrObject::get_string_attribute(RTLIL::IdString id) const +string RTLIL::AttrObject::get_string_attribute(const RTLIL::IdString &id) const { std::string value; const auto it = attributes.find(id); @@ -433,7 +428,7 @@ string RTLIL::AttrObject::get_string_attribute(RTLIL::IdString id) const return value; } -void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool &data) +void RTLIL::AttrObject::set_strpool_attribute(const RTLIL::IdString& id, const pool &data) { string attrval; for (const auto &s : data) { @@ -444,7 +439,7 @@ void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool &data) +void RTLIL::AttrObject::add_strpool_attribute(const RTLIL::IdString& id, const pool &data) { pool union_data = get_strpool_attribute(id); union_data.insert(data.begin(), data.end()); @@ -452,7 +447,7 @@ void RTLIL::AttrObject::add_strpool_attribute(RTLIL::IdString id, const pool RTLIL::AttrObject::get_strpool_attribute(RTLIL::IdString id) const +pool RTLIL::AttrObject::get_strpool_attribute(const RTLIL::IdString &id) const { pool data; if (attributes.count(id) != 0) @@ -477,7 +472,7 @@ vector RTLIL::AttrObject::get_hdlname_attribute() const return split_tokens(get_string_attribute(ID::hdlname), " "); } -void RTLIL::AttrObject::set_intvec_attribute(RTLIL::IdString id, const vector &data) +void RTLIL::AttrObject::set_intvec_attribute(const RTLIL::IdString& id, const vector &data) { std::stringstream attrval; for (auto &i : data) { @@ -488,7 +483,7 @@ void RTLIL::AttrObject::set_intvec_attribute(RTLIL::IdString id, const vector RTLIL::AttrObject::get_intvec_attribute(RTLIL::IdString id) const +vector RTLIL::AttrObject::get_intvec_attribute(const RTLIL::IdString &id) const { vector data; auto it = attributes.find(id); @@ -506,7 +501,7 @@ vector RTLIL::AttrObject::get_intvec_attribute(RTLIL::IdString id) const return data; } -bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) const +bool RTLIL::Selection::selected_module(const RTLIL::IdString &mod_name) const { if (full_selection) return true; @@ -517,7 +512,7 @@ bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) const return false; } -bool RTLIL::Selection::selected_whole_module(RTLIL::IdString mod_name) const +bool RTLIL::Selection::selected_whole_module(const RTLIL::IdString &mod_name) const { if (full_selection) return true; @@ -526,7 +521,7 @@ bool RTLIL::Selection::selected_whole_module(RTLIL::IdString mod_name) const return false; } -bool RTLIL::Selection::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const +bool RTLIL::Selection::selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const { if (full_selection) return true; @@ -638,12 +633,12 @@ RTLIL::ObjRange RTLIL::Design::modules() return RTLIL::ObjRange(&modules_, &refcount_modules_); } -RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name) +RTLIL::Module *RTLIL::Design::module(const RTLIL::IdString& name) { return modules_.count(name) ? modules_.at(name) : NULL; } -const RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name) const +const RTLIL::Module *RTLIL::Design::module(const RTLIL::IdString& name) const { return modules_.count(name) ? modules_.at(name) : NULL; } @@ -825,7 +820,7 @@ void RTLIL::Design::optimize() it.second.optimize(this); } -bool RTLIL::Design::selected_module(RTLIL::IdString mod_name) const +bool RTLIL::Design::selected_module(const RTLIL::IdString& mod_name) const { if (!selected_active_module.empty() && mod_name != selected_active_module) return false; @@ -834,7 +829,7 @@ bool RTLIL::Design::selected_module(RTLIL::IdString mod_name) const return selection_stack.back().selected_module(mod_name); } -bool RTLIL::Design::selected_whole_module(RTLIL::IdString mod_name) const +bool RTLIL::Design::selected_whole_module(const RTLIL::IdString& mod_name) const { if (!selected_active_module.empty() && mod_name != selected_active_module) return false; @@ -843,7 +838,7 @@ bool RTLIL::Design::selected_whole_module(RTLIL::IdString mod_name) const return selection_stack.back().selected_whole_module(mod_name); } -bool RTLIL::Design::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const +bool RTLIL::Design::selected_member(const RTLIL::IdString& mod_name, const RTLIL::IdString& memb_name) const { if (!selected_active_module.empty() && mod_name != selected_active_module) return false; @@ -987,7 +982,7 @@ RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, const dictname.c_str(), cell->type.c_str(), __FILE__, linenr, buf.str().c_str()); } - int param(RTLIL::IdString name) + int param(const RTLIL::IdString& name) { auto it = cell->parameters.find(name); if (it == cell->parameters.end()) @@ -1021,7 +1016,7 @@ namespace { return it->second.as_int(); } - int param_bool(RTLIL::IdString name) + int param_bool(const RTLIL::IdString& name) { int v = param(name); if (GetSize(cell->parameters.at(name)) > 32) @@ -1031,7 +1026,7 @@ namespace { return v; } - int param_bool(RTLIL::IdString name, bool expected) + int param_bool(const RTLIL::IdString& name, bool expected) { int v = param_bool(name); if (v != expected) @@ -1039,14 +1034,14 @@ namespace { return v; } - void param_bits(RTLIL::IdString name, int width) + void param_bits(const RTLIL::IdString& name, int width) { param(name); if (GetSize(cell->parameters.at(name).bits) != width) error(__LINE__); } - void port(RTLIL::IdString name, int width) + void port(const RTLIL::IdString& name, int width) { auto it = cell->connections_.find(name); if (it == cell->connections_.end()) @@ -3259,12 +3254,12 @@ std::map *RTLIL::Cell::get_all_cells(void) } #endif -bool RTLIL::Cell::hasPort(RTLIL::IdString portname) const +bool RTLIL::Cell::hasPort(const RTLIL::IdString& portname) const { return connections_.count(portname) != 0; } -void RTLIL::Cell::unsetPort(RTLIL::IdString portname) +void RTLIL::Cell::unsetPort(const RTLIL::IdString& portname) { RTLIL::SigSpec signal; auto conn_it = connections_.find(portname); @@ -3287,7 +3282,7 @@ void RTLIL::Cell::unsetPort(RTLIL::IdString portname) } } -void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal) +void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal) { auto r = connections_.insert(portname); auto conn_it = r.first; @@ -3309,7 +3304,7 @@ void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal) conn_it->second = std::move(signal); } -const RTLIL::SigSpec &RTLIL::Cell::getPort(RTLIL::IdString portname) const +const RTLIL::SigSpec &RTLIL::Cell::getPort(const RTLIL::IdString& portname) const { return connections_.at(portname); } @@ -3328,7 +3323,7 @@ bool RTLIL::Cell::known() const return false; } -bool RTLIL::Cell::input(RTLIL::IdString portname) const +bool RTLIL::Cell::input(const RTLIL::IdString& portname) const { if (yosys_celltypes.cell_known(type)) return yosys_celltypes.cell_input(type, portname); @@ -3340,7 +3335,7 @@ bool RTLIL::Cell::input(RTLIL::IdString portname) const return false; } -bool RTLIL::Cell::output(RTLIL::IdString portname) const +bool RTLIL::Cell::output(const RTLIL::IdString& portname) const { if (yosys_celltypes.cell_known(type)) return yosys_celltypes.cell_output(type, portname); @@ -3352,22 +3347,22 @@ bool RTLIL::Cell::output(RTLIL::IdString portname) const return false; } -bool RTLIL::Cell::hasParam(RTLIL::IdString paramname) const +bool RTLIL::Cell::hasParam(const RTLIL::IdString& paramname) const { return parameters.count(paramname) != 0; } -void RTLIL::Cell::unsetParam(RTLIL::IdString paramname) +void RTLIL::Cell::unsetParam(const RTLIL::IdString& paramname) { parameters.erase(paramname); } -void RTLIL::Cell::setParam(RTLIL::IdString paramname, RTLIL::Const value) +void RTLIL::Cell::setParam(const RTLIL::IdString& paramname, RTLIL::Const value) { parameters[paramname] = std::move(value); } -const RTLIL::Const &RTLIL::Cell::getParam(RTLIL::IdString paramname) const +const RTLIL::Const &RTLIL::Cell::getParam(const RTLIL::IdString& paramname) const { const auto &it = parameters.find(paramname); if (it != parameters.end()) @@ -3472,61 +3467,6 @@ bool RTLIL::Cell::is_mem_cell() const return type.in(ID($mem), ID($mem_v2)) || has_memid(); } -RTLIL::SigChunk::SigChunk() -{ - wire = NULL; - width = 0; - offset = 0; -} - -RTLIL::SigChunk::SigChunk(const RTLIL::Const &value) -{ - wire = NULL; - data = value.bits; - width = GetSize(data); - offset = 0; -} - -RTLIL::SigChunk::SigChunk(RTLIL::Wire *wire) -{ - log_assert(wire != nullptr); - this->wire = wire; - this->width = wire->width; - this->offset = 0; -} - -RTLIL::SigChunk::SigChunk(RTLIL::Wire *wire, int offset, int width) -{ - log_assert(wire != nullptr); - this->wire = wire; - this->width = width; - this->offset = offset; -} - -RTLIL::SigChunk::SigChunk(const std::string &str) -{ - wire = NULL; - data = RTLIL::Const(str).bits; - width = GetSize(data); - offset = 0; -} - -RTLIL::SigChunk::SigChunk(int val, int width) -{ - wire = NULL; - data = RTLIL::Const(val, width).bits; - this->width = GetSize(data); - offset = 0; -} - -RTLIL::SigChunk::SigChunk(RTLIL::State bit, int width) -{ - wire = NULL; - data = RTLIL::Const(bit, width).bits; - this->width = GetSize(data); - offset = 0; -} - RTLIL::SigChunk::SigChunk(const RTLIL::SigBit &bit) { wire = bit.wire; @@ -3538,11 +3478,6 @@ RTLIL::SigChunk::SigChunk(const RTLIL::SigBit &bit) width = 1; } -RTLIL::SigChunk::SigChunk(const RTLIL::SigChunk &sigchunk) -{ - *this = sigchunk; -} - RTLIL::SigChunk RTLIL::SigChunk::extract(int offset, int length) const { RTLIL::SigChunk ret; @@ -3588,17 +3523,6 @@ bool RTLIL::SigChunk::operator !=(const RTLIL::SigChunk &other) const return true; } -RTLIL::SigSpec::SigSpec() -{ - width_ = 0; - hash_ = 0; -} - -RTLIL::SigSpec::SigSpec(const RTLIL::SigSpec &other) -{ - *this = other; -} - RTLIL::SigSpec::SigSpec(std::initializer_list parts) { cover("kernel.rtlil.sigspec.init.list"); @@ -3613,23 +3537,26 @@ RTLIL::SigSpec::SigSpec(std::initializer_list parts) append(*it--); } -RTLIL::SigSpec &RTLIL::SigSpec::operator=(const RTLIL::SigSpec &other) +RTLIL::SigSpec::SigSpec(const RTLIL::Const &value) { - cover("kernel.rtlil.sigspec.assign"); + cover("kernel.rtlil.sigspec.init.const"); - width_ = other.width_; - hash_ = other.hash_; - chunks_ = other.chunks_; - bits_ = other.bits_; - return *this; + if (GetSize(value) != 0) { + chunks_.emplace_back(value); + width_ = chunks_.back().width; + } else { + width_ = 0; + } + hash_ = 0; + check(); } -RTLIL::SigSpec::SigSpec(const RTLIL::Const &value) +RTLIL::SigSpec::SigSpec(RTLIL::Const &&value) { - cover("kernel.rtlil.sigspec.init.const"); + cover("kernel.rtlil.sigspec.init.const.move"); if (GetSize(value) != 0) { - chunks_.emplace_back(value); + chunks_.emplace_back(std::move(value)); width_ = chunks_.back().width; } else { width_ = 0; @@ -3652,6 +3579,20 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk) check(); } +RTLIL::SigSpec::SigSpec(RTLIL::SigChunk &&chunk) +{ + cover("kernel.rtlil.sigspec.init.chunk.move"); + + if (chunk.width != 0) { + chunks_.emplace_back(std::move(chunk)); + width_ = chunks_.back().width; + } else { + width_ = 0; + } + hash_ = 0; + check(); +} + RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire) { cover("kernel.rtlil.sigspec.init.wire"); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index ee918441e..ff5bdf2d7 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -414,11 +414,11 @@ namespace RTLIL return str.substr(1); } - static inline std::string unescape_id(RTLIL::IdString str) { + static inline std::string unescape_id(const RTLIL::IdString &str) { return unescape_id(str.str()); } - static inline const char *id2cstr(RTLIL::IdString str) { + static inline const char *id2cstr(const RTLIL::IdString &str) { return log_id(str); } @@ -435,7 +435,7 @@ namespace RTLIL }; struct sort_by_id_str { - bool operator()(RTLIL::IdString a, RTLIL::IdString b) const { + bool operator()(const RTLIL::IdString &a, const RTLIL::IdString &b) const { return strcmp(a.c_str(), b.c_str()) < 0; } }; @@ -635,7 +635,7 @@ struct RTLIL::Const int flags; std::vector bits; - Const(); + Const() : flags(RTLIL::CONST_FLAG_NONE) {} Const(const std::string &str); Const(int val, int width = 32); Const(RTLIL::State bit, int width = 1); @@ -696,21 +696,21 @@ struct RTLIL::AttrObject { dict attributes; - bool has_attribute(RTLIL::IdString id) const; + bool has_attribute(const RTLIL::IdString &id) const; - void set_bool_attribute(RTLIL::IdString id, bool value=true); - bool get_bool_attribute(RTLIL::IdString id) const; + void set_bool_attribute(const RTLIL::IdString &id, bool value=true); + bool get_bool_attribute(const RTLIL::IdString &id) const; bool get_blackbox_attribute(bool ignore_wb=false) const { return get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox)); } - void set_string_attribute(RTLIL::IdString id, string value); - string get_string_attribute(RTLIL::IdString id) const; + void set_string_attribute(const RTLIL::IdString& id, string value); + string get_string_attribute(const RTLIL::IdString &id) const; - void set_strpool_attribute(RTLIL::IdString id, const pool &data); - void add_strpool_attribute(RTLIL::IdString id, const pool &data); - pool get_strpool_attribute(RTLIL::IdString id) const; + void set_strpool_attribute(const RTLIL::IdString& id, const pool &data); + void add_strpool_attribute(const RTLIL::IdString& id, const pool &data); + pool get_strpool_attribute(const RTLIL::IdString &id) const; void set_src_attribute(const std::string &src) { set_string_attribute(ID::src, src); @@ -722,8 +722,8 @@ struct RTLIL::AttrObject void set_hdlname_attribute(const vector &hierarchy); vector get_hdlname_attribute() const; - void set_intvec_attribute(RTLIL::IdString id, const vector &data); - vector get_intvec_attribute(RTLIL::IdString id) const; + void set_intvec_attribute(const RTLIL::IdString& id, const vector &data); + vector get_intvec_attribute(const RTLIL::IdString &id) const; }; struct RTLIL::SigChunk @@ -732,16 +732,15 @@ struct RTLIL::SigChunk std::vector data; // only used if wire == NULL, LSB at index 0 int width, offset; - SigChunk(); - SigChunk(const RTLIL::Const &value); - SigChunk(RTLIL::Wire *wire); - SigChunk(RTLIL::Wire *wire, int offset, int width = 1); - SigChunk(const std::string &str); - SigChunk(int val, int width = 32); - SigChunk(RTLIL::State bit, int width = 1); + SigChunk() : wire(nullptr), width(0), offset(0) {} + SigChunk(const RTLIL::Const &value) : wire(nullptr), data(value.bits), width(GetSize(data)), offset(0) {} + SigChunk(RTLIL::Const &&value) : wire(nullptr), data(std::move(value.bits)), width(GetSize(data)), offset(0) {} + SigChunk(RTLIL::Wire *wire) : wire(wire), width(GetSize(wire)), offset(0) {} + SigChunk(RTLIL::Wire *wire, int offset, int width = 1) : wire(wire), width(width), offset(offset) {} + SigChunk(const std::string &str) : SigChunk(RTLIL::Const(str)) {} + SigChunk(int val, int width = 32) : SigChunk(RTLIL::Const(val, width)) {} + SigChunk(RTLIL::State bit, int width = 1) : SigChunk(RTLIL::Const(bit, width)) {} SigChunk(const RTLIL::SigBit &bit); - SigChunk(const RTLIL::SigChunk &sigchunk); - RTLIL::SigChunk &operator =(const RTLIL::SigChunk &other) = default; RTLIL::SigChunk extract(int offset, int length) const; inline int size() const { return width; } @@ -827,13 +826,13 @@ private: friend struct RTLIL::Module; public: - SigSpec(); - SigSpec(const RTLIL::SigSpec &other); + SigSpec() : width_(0), hash_(0) {} SigSpec(std::initializer_list parts); - RTLIL::SigSpec &operator=(const RTLIL::SigSpec &other); SigSpec(const RTLIL::Const &value); + SigSpec(RTLIL::Const &&value); SigSpec(const RTLIL::SigChunk &chunk); + SigSpec(RTLIL::SigChunk &&chunk); SigSpec(RTLIL::Wire *wire); SigSpec(RTLIL::Wire *wire, int offset, int width = 1); SigSpec(const std::string &str); @@ -846,21 +845,6 @@ public: SigSpec(const std::set &bits); explicit SigSpec(bool bit); - SigSpec(RTLIL::SigSpec &&other) { - width_ = other.width_; - hash_ = other.hash_; - chunks_ = std::move(other.chunks_); - bits_ = std::move(other.bits_); - } - - const RTLIL::SigSpec &operator=(RTLIL::SigSpec &&other) { - width_ = other.width_; - hash_ = other.hash_; - chunks_ = std::move(other.chunks_); - bits_ = std::move(other.bits_); - return *this; - } - size_t get_hash() const { if (!hash_) hash(); return hash_; @@ -985,9 +969,9 @@ struct RTLIL::Selection Selection(bool full = true) : full_selection(full) { } - bool selected_module(RTLIL::IdString mod_name) const; - bool selected_whole_module(RTLIL::IdString mod_name) const; - bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const; + bool selected_module(const RTLIL::IdString &mod_name) const; + bool selected_whole_module(const RTLIL::IdString &mod_name) const; + bool selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const; void optimize(RTLIL::Design *design); template void select(T1 *module) { @@ -1053,11 +1037,11 @@ struct RTLIL::Design ~Design(); RTLIL::ObjRange modules(); - RTLIL::Module *module(RTLIL::IdString name); - const RTLIL::Module *module(RTLIL::IdString name) const; + RTLIL::Module *module(const RTLIL::IdString &name); + const RTLIL::Module *module(const RTLIL::IdString &name) const; RTLIL::Module *top_module(); - bool has(RTLIL::IdString id) const { + bool has(const RTLIL::IdString &id) const { return modules_.count(id) != 0; } @@ -1082,9 +1066,9 @@ struct RTLIL::Design void check(); void optimize(); - bool selected_module(RTLIL::IdString mod_name) const; - bool selected_whole_module(RTLIL::IdString mod_name) const; - bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const; + bool selected_module(const RTLIL::IdString &mod_name) const; + bool selected_whole_module(const RTLIL::IdString &mod_name) const; + bool selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const; bool selected_module(RTLIL::Module *mod) const; bool selected_whole_module(RTLIL::Module *mod) const; @@ -1165,7 +1149,7 @@ public: virtual ~Module(); virtual RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, bool mayfail = false); virtual RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, const dict &interfaces, const dict &modports, bool mayfail = false); - virtual size_t count_id(RTLIL::IdString id); + virtual size_t count_id(const RTLIL::IdString& id); virtual void expand_interfaces(RTLIL::Design *design, const dict &local_interfaces); virtual bool reprocess_if_necessary(RTLIL::Design *design); @@ -1200,20 +1184,20 @@ public: return design->selected_member(name, member->name); } - RTLIL::Wire* wire(RTLIL::IdString id) { + RTLIL::Wire* wire(const RTLIL::IdString &id) { auto it = wires_.find(id); return it == wires_.end() ? nullptr : it->second; } - RTLIL::Cell* cell(RTLIL::IdString id) { + RTLIL::Cell* cell(const RTLIL::IdString &id) { auto it = cells_.find(id); return it == cells_.end() ? nullptr : it->second; } - const RTLIL::Wire* wire(RTLIL::IdString id) const{ + const RTLIL::Wire* wire(const RTLIL::IdString &id) const{ auto it = wires_.find(id); return it == wires_.end() ? nullptr : it->second; } - const RTLIL::Cell* cell(RTLIL::IdString id) const { + const RTLIL::Cell* cell(const RTLIL::IdString &id) const { auto it = cells_.find(id); return it == cells_.end() ? nullptr : it->second; } @@ -1483,6 +1467,10 @@ public: #endif }; +inline int GetSize(RTLIL::Wire *wire) { + return wire->width; +} + struct RTLIL::Memory : public RTLIL::AttrObject { unsigned int hashidx_; @@ -1521,22 +1509,22 @@ public: dict parameters; // access cell ports - bool hasPort(RTLIL::IdString portname) const; - void unsetPort(RTLIL::IdString portname); - void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal); - const RTLIL::SigSpec &getPort(RTLIL::IdString portname) const; + bool hasPort(const RTLIL::IdString &portname) const; + void unsetPort(const RTLIL::IdString &portname); + void setPort(const RTLIL::IdString &portname, RTLIL::SigSpec signal); + const RTLIL::SigSpec &getPort(const RTLIL::IdString &portname) const; const dict &connections() const; // information about cell ports bool known() const; - bool input(RTLIL::IdString portname) const; - bool output(RTLIL::IdString portname) const; + bool input(const RTLIL::IdString &portname) const; + bool output(const RTLIL::IdString &portname) const; // access cell parameters - bool hasParam(RTLIL::IdString paramname) const; - void unsetParam(RTLIL::IdString paramname); - void setParam(RTLIL::IdString paramname, RTLIL::Const value); - const RTLIL::Const &getParam(RTLIL::IdString paramname) const; + bool hasParam(const RTLIL::IdString ¶mname) const; + void unsetParam(const RTLIL::IdString ¶mname); + void setParam(const RTLIL::IdString ¶mname, RTLIL::Const value); + const RTLIL::Const &getParam(const RTLIL::IdString ¶mname) const; void sort(); void check(); diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 11df235e4..a56a066fe 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -534,11 +534,6 @@ std::string escape_filename_spaces(const std::string& filename) return out; } -int GetSize(RTLIL::Wire *wire) -{ - return wire->width; -} - bool already_setup = false; void yosys_setup() diff --git a/kernel/yosys.h b/kernel/yosys.h index 448f896d4..b5b1553f2 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -287,7 +287,7 @@ void remove_directory(std::string dirname); std::string escape_filename_spaces(const std::string& filename); template int GetSize(const T &obj) { return obj.size(); } -int GetSize(RTLIL::Wire *wire); +inline int GetSize(RTLIL::Wire *wire); extern int autoidx; extern int yosys_xtrace; -- cgit v1.2.3 From 23a39d707eca0ef9095bfaac7bf8c02dafd41619 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 28 Jul 2022 00:18:37 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 067e0bbf0..f0c96c474 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.19+25 +YOSYS_VER := 0.19+34 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From d19f9d0b66280d6d73275dbb030b91381ccda48b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miodrag=20Milanovi=C4=87?= Date: Thu, 28 Jul 2022 12:32:19 +0200 Subject: Update README --- frontends/verific/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verific/README b/frontends/verific/README index 952fb1e0c..921873af3 100644 --- a/frontends/verific/README +++ b/frontends/verific/README @@ -1,7 +1,7 @@ This directory contains Verific bindings for Yosys. -Use Tabby CAD Suite from YosysHQ if you need Yosys+Verifc. +Use Tabby CAD Suite from YosysHQ if you need Yosys+Verific. https://www.yosyshq.com/ Contact YosysHQ at contact@yosyshq.com for free evaluation -- cgit v1.2.3 From 30a4218f537e76d1b3f2be0859662a7055985e27 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 29 Jul 2022 00:17:18 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f0c96c474..717aaf30f 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.19+34 +YOSYS_VER := 0.19+36 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From 52a4a89265b656a97bba441ac8f5c768bdd5c73e Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 29 Jul 2022 17:10:31 +0200 Subject: Setting wire upto in verific import --- frontends/verific/verific.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index fd6208e86..ab527a253 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1124,6 +1124,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(portbus->Name()), portbus->Size()); wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex()); + wire->upto = portbus->IsUp(); import_attributes(wire->attributes, portbus, nl); bool portbus_input = portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_IN; @@ -1144,7 +1145,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma wire->port_output = true; } net = portbus->ElementAtIndex(i)->GetNet(); - RTLIL::SigBit bit(wire, i - wire->start_offset); + int bitidx = wire->upto ? (wire->width - 1 - (i - wire->start_offset)) : (i - wire->start_offset); + RTLIL::SigBit bit(wire, bitidx); if (net_map.count(net) == 0) net_map[net] = bit; else if (bit_input) @@ -1308,6 +1310,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma RTLIL::Wire *wire = module->addWire(wire_name, netbus->Size()); wire->start_offset = min(netbus->LeftIndex(), netbus->RightIndex()); + wire->upto = netbus->IsUp(); MapIter mibus; FOREACH_NET_OF_NETBUS(netbus, mibus, net) { if (net) @@ -1322,7 +1325,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma { if (netbus->ElementAtIndex(i)) { - int bitidx = i - wire->start_offset; + int bitidx = wire->upto ? (wire->width - 1 - (i - wire->start_offset)) : (i - wire->start_offset); net = netbus->ElementAtIndex(i); RTLIL::SigBit bit(wire, bitidx); -- cgit v1.2.3 From 6f792e2223cc87f72bbd4cc9f1820e5b72dfec3e Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 1 Aug 2022 12:34:51 +0200 Subject: Update documentation --- manual/command-reference-manual.tex | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/manual/command-reference-manual.tex b/manual/command-reference-manual.tex index 28b99f3a6..644f81d95 100644 --- a/manual/command-reference-manual.tex +++ b/manual/command-reference-manual.tex @@ -7407,6 +7407,10 @@ in order to avoid a name collision with the built in commands. If any arguments are specified, these arguments are provided to the script via the standard $argc and $argv variables. + +Note, tcl will not recieve the output of any yosys command. If the output +of the tcl commands are needed, use the yosys command 'tee' to redirect yosys's +output to a temporary file. \end{lstlisting} \section{techmap -- generic technology mapper} -- cgit v1.2.3 From 7d4f87d69f06d2cf6259fb445275a5f479bf74ee Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 2 Aug 2022 00:19:48 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 717aaf30f..daa2ebc5a 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.19+36 +YOSYS_VER := 0.19+42 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From 4f0ee383c9b48174c916540d7aa1eb624a4a9a25 Mon Sep 17 00:00:00 2001 From: Aki Van Ness Date: Tue, 2 Aug 2022 06:58:41 -0400 Subject: backend: jny: updated the `JnyWriter` to emite a new "invocation" entry as well as a "$schema" entry to point to the location the schema will be at --- backends/jny/jny.cc | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/backends/jny/jny.cc b/backends/jny/jny.cc index d801b144c..2b8d51b76 100644 --- a/backends/jny/jny.cc +++ b/backends/jny/jny.cc @@ -27,6 +27,8 @@ #include #include #include +#include +#include USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -116,17 +118,17 @@ struct JnyWriter _include_connections(connections), _include_attributes(attributes), _include_properties(properties) { } - void write_metadata(Design *design, uint16_t indent_level = 0) + void write_metadata(Design *design, uint16_t indent_level = 0, std::string invk = "") { log_assert(design != nullptr); design->sort(); f << "{\n"; + f << " \"$schema\": \"https://raw.githubusercontent.com/YosysHQ/yosys/master/misc/jny.schema.json\",\n"; f << stringf(" \"generator\": \"%s\",\n", escape_string(yosys_version_str).c_str()); - // XXX(aki): Replace this with a proper version info eventually:tm: - f << " \"version\": \"0.0.0\",\n"; - + f << " \"version\": \"0.0.1\",\n"; + f << " \"invocation\": \"" << escape_string(invk) << "\",\n"; f << " \"features\": ["; size_t fnum{0}; @@ -409,11 +411,12 @@ struct JnyWriter struct JnyBackend : public Backend { JnyBackend() : Backend("jny", "generate design metadata") { } void help() override { - // XXX(aki): TODO: explicitly document the JSON schema // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" jny [options] [selection]\n"); log("\n"); + log("Write JSON netlist metadata for the current design\n"); + log("\n"); log(" -no-connections\n"); log(" Don't include connection information in the netlist output.\n"); log("\n"); @@ -423,8 +426,8 @@ struct JnyBackend : public Backend { log(" -no-properties\n"); log(" Don't include property information in the netlist output.\n"); log("\n"); - log("Write a JSON metadata for the current design\n"); - log("\n"); + log("The JSON schema for JNY output files is located in the \"jny.schema.json\" file\n"); + log("which is located at \"https://raw.githubusercontent.com/YosysHQ/yosys/master/misc/jny.schema.json\"\n"); log("\n"); } @@ -453,12 +456,22 @@ struct JnyBackend : public Backend { break; } + + // Compose invocation line + std::ostringstream invk; + if (!args.empty()) { + std::copy(args.begin(), args.end(), + std::ostream_iterator(invk, " ") + ); + } + invk << filename; + extra_args(f, filename, args, argidx); log_header(design, "Executing jny backend.\n"); JnyWriter jny_writer(*f, false, connections, attributes, properties); - jny_writer.write_metadata(design); + jny_writer.write_metadata(design, 0, invk.str()); } } JnyBackend; @@ -472,7 +485,7 @@ struct JnyPass : public Pass { log("\n"); log(" jny [options] [selection]\n"); log("\n"); - log("Write a JSON netlist metadata for the current design\n"); + log("Write JSON netlist metadata for the current design\n"); log("\n"); log(" -o \n"); log(" write to the specified file.\n"); @@ -520,6 +533,15 @@ struct JnyPass : public Pass { break; } + + // Compose invocation line + std::ostringstream invk; + if (!args.empty()) { + std::copy(args.begin(), args.end(), + std::ostream_iterator(invk, " ") + ); + } + extra_args(args, argidx, design); std::ostream *f; @@ -534,13 +556,14 @@ struct JnyPass : public Pass { log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); } f = ff; + invk << filename; } else { f = &buf; } JnyWriter jny_writer(*f, false, connections, attributes, properties); - jny_writer.write_metadata(design); + jny_writer.write_metadata(design, 0, invk.str()); if (!filename.empty()) { delete f; -- cgit v1.2.3 From e3074c044a113d9f03877ac94ca5641101e4f883 Mon Sep 17 00:00:00 2001 From: Aki Van Ness Date: Tue, 2 Aug 2022 07:23:45 -0400 Subject: misc: Added JNY schema definition --- misc/jny.schema.json | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 misc/jny.schema.json diff --git a/misc/jny.schema.json b/misc/jny.schema.json new file mode 100644 index 000000000..0fff8ee57 --- /dev/null +++ b/misc/jny.schema.json @@ -0,0 +1,193 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://raw.githubusercontent.com/YosysHQ/yosys/master/misc/jny.schema.json", + "title": "Yosys JSON Netlist metadata", + "description": "Yosys JSON Netlist", + "type": "object", + "properties": { + "generator": { + "type": "string", + "description": "JNY File Generator" + }, + "version": { + "type": "string", + "description": "JNY Version" + }, + "invocation": { + "type": "string", + "description": "Invocation line that generated the JNY metadata" + }, + "features": { + "type": "array", + "description": "What information is contained in the JNY file", + "items": { + "type": "string" + } + }, + "modules": { + "type": "array", + "items": { "$ref": "#/$defs/module" } + } + }, + "required": [ + "generator", + "version", + "invocation", + "features" + ], + "$defs": { + "module": { + "type": "object", + "description": "Module definition", + "properties": { + "name": { + "type": "string", + "description": "Module Name" + }, + "cell_sorts": { + "type": "array", + "description": "", + "items": { "$ref": "#/$defs/cell_sort" } + }, + "connections": { + "type": "array", + "description": "Cell connections", + "items": { "$ref": "#/$defs/connection" } + }, + "attributes": { + "type": "object", + "description": "Attributes attached to the module" + }, + "parameters": { + "type": "object", + "description": "Parameters attached to the module" + } + }, + "required": [ + "name", + "cell_sorts" + ] + }, + "cell_sort": { + "type": "object", + "description": "Describes a type of cell", + "properties": { + "type": { + "type": "string", + "description": "Type of cell" + }, + "ports": { + "type": "array", + "description": "Cell ports", + "items": { "$ref": "#/$defs/port" } + } + , + "cells": { + "type": "array", + "description": "Cells of cell_sort", + "items": { "$ref": "#/$defs/cell" } + } + }, + "required": [ + "type", + "ports", + "cells" + ] + }, + "connection": { + "type": "object", + "description": "A connection within a module or cell", + "properties": { + "name": { + "type": "string", + "description": "Connection name" + }, + "signals": { + "type": "array", + "description": "Signals that compose the connection", + "items": { "$ref": "#/$defs/signal" } + } + }, + "required": [ + "name", + "signals" + ] + }, + "port": { + "type": "object", + "description": "Cell port description", + "properties": { + "name": { + "type": "string", + "description": "Port name" + }, + "direction": { + "type": "string", + "description": "Port direction", + "enum": ["i", "o", "io", ""] + }, + "range": { + "type": "array", + "description": "Port width [MSB, LSB]", + "items": { + "type": "number" + }, + "minContains": 1, + "maxContains": 2 + } + }, + "required": [ + "name", + "direction", + "range" + ] + }, + "cell": { + "type": "object", + "description": "Module cell definition", + "properties": { + "name": { + "type": "string", + "description": "Cell name" + }, + "connections": { + "type": "array", + "description": "Cell connections", + "items": { "$ref": "#/$defs/connection" } + }, + "attributes": { + "type": "object", + "description": "Attributes attached to the cell" + }, + "parameters": { + "type": "object", + "description": "Parameters attached to the cell" + } + }, + "required": [ + "name" + ] + }, + "signal": { + "type": "object", + "description": "A signal definition", + "parameters": { + "width": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["wire", "chunk"] + }, + "const": { + "type": "boolean" + } + }, + "required": [ + "width", + "type", + "const" + ] + } + } +} -- cgit v1.2.3 From 6af5e74f95abdead1c4c900e0c1951b71dcf80c8 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 2 Aug 2022 20:16:41 +0200 Subject: smt2: Fix $shift/$shiftx with negative shift ammounts Fixes #3431, fixes #3344 --- backends/smt2/smt2.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index 7481e0510..f6c3560c1 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -449,7 +449,7 @@ struct Smt2Worker bool is_signed = cell->getParam(ID::A_SIGNED).as_bool(); int width = GetSize(sig_y); - if (type == 's' || type == 'd' || type == 'b') { + if (type == 's' || type == 'S' || type == 'd' || type == 'b') { width = max(width, GetSize(cell->getPort(ID::A))); if (cell->hasPort(ID::B)) width = max(width, GetSize(cell->getPort(ID::B))); @@ -462,7 +462,7 @@ struct Smt2Worker if (cell->hasPort(ID::B)) { sig_b = cell->getPort(ID::B); - sig_b.extend_u0(width, is_signed && !(type == 's')); + sig_b.extend_u0(width, (type == 'S') || (is_signed && !(type == 's'))); } std::string processed_expr; @@ -619,8 +619,8 @@ struct Smt2Worker if (cell->type.in(ID($shift), ID($shiftx))) { if (cell->getParam(ID::B_SIGNED).as_bool()) { return export_bvop(cell, stringf("(ite (bvsge P #b%0*d) " - "(bvlshr A B) (bvlshr A (bvneg B)))", - GetSize(cell->getPort(ID::B)), 0), 's'); + "(bvlshr A B) (bvshl A (bvneg B)))", + GetSize(cell->getPort(ID::B)), 0), 'S'); // type 'S' sign extends B } else { return export_bvop(cell, "(bvlshr A B)", 's'); } -- cgit v1.2.3 From e9893133174db0e195a35f2480aba8712c05d91a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 3 Aug 2022 00:20:46 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index daa2ebc5a..ba6d00a10 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.19+42 +YOSYS_VER := 0.19+45 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From 6a1d98b816a15b9f06a3a4621a9ae390c30b7494 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 3 Aug 2022 10:30:58 +0200 Subject: Update manual and changelog --- CHANGELOG | 6 ++++++ manual/command-reference-manual.tex | 3 +++ 2 files changed, 9 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 54c385cd8..341c9957c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,12 @@ List of major changes and improvements between releases Yosys 0.19 .. Yosys 0.19-dev -------------------------- + * New commands and options + - Added option "-wb" to "read_liberty" pass + + * Various + - Added support for $modfloor operator to cxxrtl backend + - Support build on OpenBSD Yosys 0.18 .. Yosys 0.19 -------------------------- diff --git a/manual/command-reference-manual.tex b/manual/command-reference-manual.tex index 644f81d95..411feb05d 100644 --- a/manual/command-reference-manual.tex +++ b/manual/command-reference-manual.tex @@ -4011,6 +4011,9 @@ Read cells from liberty file as modules into current design. -lib only create empty blackbox modules + -wb + mark imported cells as whiteboxes + -nooverwrite ignore re-definitions of modules. (the default behavior is to create an error message if the existing module is not a blackbox -- cgit v1.2.3 From 3f7042d1145b3204115251a091c75dd23d572eba Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 3 Aug 2022 13:44:13 +0200 Subject: update manual to latest --- manual/command-reference-manual.tex | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/manual/command-reference-manual.tex b/manual/command-reference-manual.tex index 411feb05d..bc25c35cd 100644 --- a/manual/command-reference-manual.tex +++ b/manual/command-reference-manual.tex @@ -2610,7 +2610,7 @@ Tristate PADS (-toutpad, -tinoutpad) always operate in -bits mode. \begin{lstlisting}[numbers=left,frame=single] jny [options] [selection] -Write a JSON netlist metadata for the current design +Write JSON netlist metadata for the current design -o write to the specified file. @@ -8531,6 +8531,8 @@ http://bygone.clairexen.net/intersynth/ \begin{lstlisting}[numbers=left,frame=single] jny [options] [selection] +Write JSON netlist metadata for the current design + -no-connections Don't include connection information in the netlist output. @@ -8540,7 +8542,8 @@ http://bygone.clairexen.net/intersynth/ -no-properties Don't include property information in the netlist output. -Write a JSON metadata for the current design +The JSON schema for JNY output files is located in the "jny.schema.json" file +which is located at "https://raw.githubusercontent.com/YosysHQ/yosys/master/misc/jny.schema.json" \end{lstlisting} \section{write\_json -- write design to a JSON file} -- cgit v1.2.3 From a07b06d5e7b3f5cd9b9c8a1b1a8e7718172c8bbc Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 3 Aug 2022 13:52:01 +0200 Subject: Update Changelog --- CHANGELOG | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 341c9957c..fde400117 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,13 @@ Yosys 0.19 .. Yosys 0.19-dev * Various - Added support for $modfloor operator to cxxrtl backend - Support build on OpenBSD + - Fixed smt2 backend use of $shift/$shiftx with negative shift amounts, + which affects bit/part-select assignments with a dynamic index. Shift + operators were not affected. + + * Verific support + - Proper import of port ranges into Yosys, may result in reversed + bit-order of top-level ports for some synthesis flows. Yosys 0.18 .. Yosys 0.19 -------------------------- -- cgit v1.2.3 From 4fcb95ed087263d6e55662a18ceac1722100c7d0 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 3 Aug 2022 13:53:41 +0200 Subject: Release version 0.20 --- CHANGELOG | 2 +- Makefile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fde400117..42f264686 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.19 .. Yosys 0.19-dev +Yosys 0.19 .. Yosys 0.20 -------------------------- * New commands and options - Added option "-wb" to "read_liberty" pass diff --git a/Makefile b/Makefile index ba6d00a10..0232a8101 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.19+45 +YOSYS_VER := 0.20 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -147,7 +147,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline a45c131.. | wc -l`/;" Makefile +# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline a45c131.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # -- cgit v1.2.3 From 733902c81e1be8e8eee880697ce967fb91e00d05 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 3 Aug 2022 13:57:14 +0200 Subject: Next dev cycle --- CHANGELOG | 3 +++ Makefile | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 42f264686..434872248 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,9 @@ List of major changes and improvements between releases ======================================================= +Yosys 0.20 .. Yosys 0.20-dev +-------------------------- + Yosys 0.19 .. Yosys 0.20 -------------------------- * New commands and options diff --git a/Makefile b/Makefile index 0232a8101..312b51a43 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.20 +YOSYS_VER := 0.20+0 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -147,7 +147,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: -# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline a45c131.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 4fcb95e.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # -- cgit v1.2.3 From 60a787fa50062169c1aae4ecb199d13c0b6f25b6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 4 Aug 2022 00:18:16 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 312b51a43..b794e9886 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.20+0 +YOSYS_VER := 0.20+1 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From 2b1aeb44d98f4aafc73a66cdd02092571d725ee4 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 8 Aug 2022 11:57:28 +0200 Subject: verific - make filepath handling compatible with verilog frontend --- frontends/verific/verific.cc | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index ab527a253..e516a5ec7 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2828,9 +2828,11 @@ struct VerificPass : public Pass { for (auto &ext : verific_libexts) veri_file::AddLibExt(ext.c_str()); - while (argidx < GetSize(args)) - file_names.Insert(args[argidx++].c_str()); - + while (argidx < GetSize(args)) { + std::string filename(args[argidx++]); + rewrite_filename(filename); + file_names.Insert(strdup(filename.c_str())); + } if (!veri_file::AnalyzeMultipleFiles(&file_names, verilog_mode, work.c_str(), veri_file::MFCU)) { verific_error_msg.clear(); log_cmd_error("Reading Verilog/SystemVerilog sources failed.\n"); @@ -2843,36 +2845,48 @@ struct VerificPass : public Pass { #ifdef VERIFIC_VHDL_SUPPORT if (GetSize(args) > argidx && args[argidx] == "-vhdl87") { vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1987").c_str()); - for (argidx++; argidx < GetSize(args); argidx++) - if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_87)) - log_cmd_error("Reading `%s' in VHDL_87 mode failed.\n", args[argidx].c_str()); + for (argidx++; argidx < GetSize(args); argidx++) { + std::string filename(args[argidx]); + rewrite_filename(filename); + if (!vhdl_file::Analyze(filename.c_str(), work.c_str(), vhdl_file::VHDL_87)) + log_cmd_error("Reading `%s' in VHDL_87 mode failed.\n", filename.c_str()); + } verific_import_pending = true; goto check_error; } if (GetSize(args) > argidx && args[argidx] == "-vhdl93") { vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str()); - for (argidx++; argidx < GetSize(args); argidx++) - if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_93)) - log_cmd_error("Reading `%s' in VHDL_93 mode failed.\n", args[argidx].c_str()); + for (argidx++; argidx < GetSize(args); argidx++) { + std::string filename(args[argidx]); + rewrite_filename(filename); + if (!vhdl_file::Analyze(filename.c_str(), work.c_str(), vhdl_file::VHDL_93)) + log_cmd_error("Reading `%s' in VHDL_93 mode failed.\n", filename.c_str()); + } verific_import_pending = true; goto check_error; } if (GetSize(args) > argidx && args[argidx] == "-vhdl2k") { vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str()); - for (argidx++; argidx < GetSize(args); argidx++) - if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_2K)) - log_cmd_error("Reading `%s' in VHDL_2K mode failed.\n", args[argidx].c_str()); + for (argidx++; argidx < GetSize(args); argidx++) { + std::string filename(args[argidx]); + rewrite_filename(filename); + if (!vhdl_file::Analyze(filename.c_str(), work.c_str(), vhdl_file::VHDL_2K)) + log_cmd_error("Reading `%s' in VHDL_2K mode failed.\n", filename.c_str()); + } verific_import_pending = true; goto check_error; } if (GetSize(args) > argidx && (args[argidx] == "-vhdl2008" || args[argidx] == "-vhdl")) { vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_2008").c_str()); - for (argidx++; argidx < GetSize(args); argidx++) - if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_2008)) - log_cmd_error("Reading `%s' in VHDL_2008 mode failed.\n", args[argidx].c_str()); + for (argidx++; argidx < GetSize(args); argidx++) { + std::string filename(args[argidx]); + rewrite_filename(filename); + if (!vhdl_file::Analyze(filename.c_str(), work.c_str(), vhdl_file::VHDL_2008)) + log_cmd_error("Reading `%s' in VHDL_2008 mode failed.\n", filename.c_str()); + } verific_import_pending = true; goto check_error; } -- cgit v1.2.3 From 6c65ca4e50cc6712d9293b9630afdf67af89ef61 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 8 Aug 2022 16:13:33 +0200 Subject: Encode filename unprintable chars --- frontends/ast/genrtlil.cc | 16 ++++++++-------- frontends/ast/simplify.cc | 36 ++++++++++++++++++------------------ frontends/verific/verific.cc | 2 +- kernel/rtlil.h | 15 +++++++++++++++ 4 files changed, 42 insertions(+), 27 deletions(-) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index d81c53dfb..9327b34ee 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -45,7 +45,7 @@ using namespace AST_INTERNAL; // helper function for creating RTLIL code for unary operations static RTLIL::SigSpec uniop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &arg, bool gen_attributes = true) { - IdString name = stringf("%s$%s:%d$%d", type.c_str(), that->filename.c_str(), that->location.first_line, autoidx++); + IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, type); set_src_attr(cell, that); @@ -77,7 +77,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s return; } - IdString name = stringf("$extend$%s:%d$%d", that->filename.c_str(), that->location.first_line, autoidx++); + IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, ID($pos)); set_src_attr(cell, that); @@ -104,7 +104,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s // helper function for creating RTLIL code for binary operations static RTLIL::SigSpec binop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) { - IdString name = stringf("%s$%s:%d$%d", type.c_str(), that->filename.c_str(), that->location.first_line, autoidx++); + IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, type); set_src_attr(cell, that); @@ -138,7 +138,7 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const log_assert(cond.size() == 1); std::stringstream sstr; - sstr << "$ternary$" << that->filename << ":" << that->location.first_line << "$" << (autoidx++); + sstr << "$ternary$" << RTLIL::encode_filename(that->filename) << ":" << that->location.first_line << "$" << (autoidx++); RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($mux)); set_src_attr(cell, that); @@ -321,7 +321,7 @@ struct AST_INTERNAL::ProcessGenerator LookaheadRewriter la_rewriter(always); // generate process and simple root case - proc = current_module->addProcess(stringf("$proc$%s:%d$%d", always->filename.c_str(), always->location.first_line, autoidx++)); + proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(always->filename).c_str(), always->location.first_line, autoidx++)); set_src_attr(proc, always); for (auto &attr : always->attributes) { if (attr.second->type != AST_CONSTANT) @@ -1776,7 +1776,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_MEMRD: { std::stringstream sstr; - sstr << "$memrd$" << str << "$" << filename << ":" << location.first_line << "$" << (autoidx++); + sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($memrd)); set_src_attr(cell, this); @@ -1814,7 +1814,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_MEMINIT: { std::stringstream sstr; - sstr << "$meminit$" << str << "$" << filename << ":" << location.first_line << "$" << (autoidx++); + sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); SigSpec en_sig = children[2]->genRTLIL(); @@ -1869,7 +1869,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) IdString cellname; if (str.empty()) - cellname = stringf("%s$%s:%d$%d", celltype.c_str(), filename.c_str(), location.first_line, autoidx++); + cellname = stringf("%s$%s:%d$%d", celltype.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); else cellname = str; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 2d9d6dc79..49bf9af09 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1240,7 +1240,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // create the indirection wire std::stringstream sstr; - sstr << "$indirect$" << ref->name.c_str() << "$" << filename << ":" << location.first_line << "$" << (autoidx++); + sstr << "$indirect$" << ref->name.c_str() << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); std::string tmp_str = sstr.str(); add_wire_for_ref(ref, tmp_str); @@ -2127,7 +2127,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, std::swap(data_range_left, data_range_right); std::stringstream sstr; - sstr << "$mem2bits$" << str << "$" << filename << ":" << location.first_line << "$" << (autoidx++); + sstr << "$mem2bits$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); std::string wire_id = sstr.str(); AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); @@ -2714,14 +2714,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // mask and shift operations, disabled for now 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", filename.c_str(), location.first_line, autoidx++); + 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->is_logic = true; while (wire_mask->simplify(true, false, 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", filename.c_str(), location.first_line, autoidx++); + 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->is_logic = true; while (wire_data->simplify(true, false, false, 1, -1, false, false)) { } @@ -2732,7 +2732,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, shift_expr->detectSignWidth(shamt_width_hint, shamt_sign_hint); 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", filename.c_str(), location.first_line, autoidx++); + 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->is_logic = true; wire_sel->is_signed = shamt_sign_hint; @@ -2809,7 +2809,7 @@ skip_dynamic_range_lvalue_expansion:; if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME || type == AST_LIVE || type == AST_FAIR || type == AST_COVER) && current_block != NULL) { std::stringstream sstr; - sstr << "$formal$" << filename << ":" << location.first_line << "$" << (autoidx++); + sstr << "$formal$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); std::string id_check = sstr.str() + "_CHECK", id_en = sstr.str() + "_EN"; AstNode *wire_check = new AstNode(AST_WIRE); @@ -2918,7 +2918,7 @@ skip_dynamic_range_lvalue_expansion:; newNode = new AstNode(AST_BLOCK); AstNode *wire_tmp = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true))); - wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", filename.c_str(), location.first_line, autoidx++); + 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); @@ -2956,7 +2956,7 @@ skip_dynamic_range_lvalue_expansion:; (children[0]->children.size() == 1 || children[0]->children.size() == 2) && children[0]->children[0]->type == AST_RANGE) { std::stringstream sstr; - sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << location.first_line << "$" << (autoidx++); + sstr << "$memwr$" << children[0]->str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN"; int mem_width, mem_size, addr_bits; @@ -3228,7 +3228,7 @@ skip_dynamic_range_lvalue_expansion:; AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true))); - reg->str = stringf("$past$%s:%d$%d$%d", filename.c_str(), location.first_line, myidx, i); + reg->str = stringf("$past$%s:%d$%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, myidx, i); reg->is_reg = true; reg->is_signed = sign_hint; @@ -3733,7 +3733,7 @@ skip_dynamic_range_lvalue_expansion:; std::stringstream sstr; - sstr << str << "$func$" << filename << ":" << location.first_line << "$" << (autoidx++) << '.'; + sstr << str << "$func$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++) << '.'; std::string prefix = sstr.str(); AstNode *decl = current_scope[str]; @@ -4586,7 +4586,7 @@ static void mark_memories_assign_lhs_complex(dict> & if (that->type == AST_IDENTIFIER && that->id2ast && that->id2ast->type == AST_MEMORY) { AstNode *mem = that->id2ast; if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_CMPLX_LHS)) - mem2reg_places[mem].insert(stringf("%s:%d", that->filename.c_str(), that->location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(that->filename).c_str(), that->location.first_line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CMPLX_LHS; } } @@ -4614,14 +4614,14 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg // activate mem2reg if this is assigned in an async proc if (flags & AstNode::MEM2REG_FL_ASYNC) { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ASYNC)) - mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ASYNC; } // remember if this is assigned blocking (=) if (type == AST_ASSIGN_EQ) { if (!(proc_flags[mem] & AstNode::MEM2REG_FL_EQ1)) - mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1; } @@ -4638,11 +4638,11 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg // remember where this is if (flags & MEM2REG_FL_INIT) { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT)) - mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_INIT; } else { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ELSE)) - mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ELSE; } } @@ -4656,7 +4656,7 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg // flag if used after blocking assignment (in same proc) if ((proc_flags[mem] & AstNode::MEM2REG_FL_EQ1) && !(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_EQ2)) { - mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_EQ2; } } @@ -4846,7 +4846,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, children[0]->children[0]->children[0]->type != AST_CONSTANT) { std::stringstream sstr; - sstr << "$mem2reg_wr$" << children[0]->str << "$" << filename << ":" << location.first_line << "$" << (autoidx++); + sstr << "$mem2reg_wr$" << children[0]->str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; int mem_width, mem_size, addr_bits; @@ -4962,7 +4962,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, else { std::stringstream sstr; - sstr << "$mem2reg_rd$" << str << "$" << filename << ":" << location.first_line << "$" << (autoidx++); + sstr << "$mem2reg_rd$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; int mem_width, mem_size, addr_bits; diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index e516a5ec7..e0dbe1b32 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -183,7 +183,7 @@ RTLIL::IdString VerificImporter::new_verific_id(Verific::DesignObj *obj) { std::string s = stringf("$verific$%s", obj->Name()); if (obj->Linefile()) - s += stringf("$%s:%d", Verific::LineFile::GetFileName(obj->Linefile()), Verific::LineFile::GetLineNo(obj->Linefile())); + s += stringf("$%s:%d", RTLIL::encode_filename(Verific::LineFile::GetFileName(obj->Linefile())).c_str(), Verific::LineFile::GetLineNo(obj->Linefile())); s += stringf("$%d", autoidx++); return s; } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index ff5bdf2d7..db175d7e9 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -440,6 +440,21 @@ namespace RTLIL } }; + static inline std::string encode_filename(const std::string &filename) + { + std::stringstream val; + if (!std::any_of(filename.begin(), filename.end(), [](char c) { + return static_cast(c) < 33 || static_cast(c) > 126; + })) return filename; + for (unsigned char const c : filename) { + if (c < 33 || c > 126) + val << stringf("$%02x", c); + else + val << c; + } + return val.str(); + } + // see calc.cc for the implementation of this functions RTLIL::Const const_not (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); -- cgit v1.2.3 From a48dcd1d40a845cfb8b18cbe986faf0b780880be Mon Sep 17 00:00:00 2001 From: Lofty Date: Mon, 11 Apr 2022 13:21:47 +0100 Subject: rename: add -scramble-name option to randomly rename selections --- passes/cmds/rename.cc | 56 +++++++++++++++++++++++++++++++++++ tests/various/rename_scramble_name.ys | 31 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 tests/various/rename_scramble_name.ys diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc index 81da35ffe..b49d5cdc2 100644 --- a/passes/cmds/rename.cc +++ b/passes/cmds/rename.cc @@ -20,6 +20,7 @@ #include "kernel/register.h" #include "kernel/rtlil.h" #include "kernel/log.h" +#include "kernel/hashlib.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -156,6 +157,13 @@ struct RenamePass : public Pass { log("\n"); log("Rename top module.\n"); log("\n"); + log("\n"); + log(" rename -scramble-name [-seed ] [selection]\n"); + log("\n"); + log("Assign randomly-generated names to all selected wires and cells. The seed option\n"); + log("can be used to change the random number generator seed from the default, but it\n"); + log("must be non-zero.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { @@ -167,7 +175,9 @@ struct RenamePass : public Pass { bool flag_hide = false; bool flag_top = false; bool flag_output = false; + bool flag_scramble_name = false; bool got_mode = false; + unsigned int seed = 1; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -203,6 +213,11 @@ struct RenamePass : public Pass { got_mode = true; continue; } + if (arg == "-scramble-name" && !got_mode) { + flag_scramble_name = true; + got_mode = true; + continue; + } if (arg == "-pattern" && argidx+1 < args.size() && args[argidx+1].find('%') != std::string::npos) { int pos = args[++argidx].find('%'); pattern_prefix = args[argidx].substr(0, pos); @@ -211,6 +226,11 @@ struct RenamePass : public Pass { } if (arg == "-suffix" && argidx + 1 < args.size()) { cell_suffix = args[++argidx]; + continue; + } + if (arg == "-seed" && argidx+1 < args.size()) { + seed = std::stoi(args[++argidx]); + continue; } break; } @@ -329,6 +349,42 @@ struct RenamePass : public Pass { design->rename(module, new_name); } else + if (flag_scramble_name) + { + extra_args(args, argidx, design); + + if (seed == 0) + log_error("Seed for -scramble-name cannot be zero.\n"); + + for (auto module : design->selected_modules()) + { + if (module->memories.size() != 0 || module->processes.size() != 0) { + log_warning("Skipping module %s with unprocessed memories or processes\n", log_id(module)); + continue; + } + + dict new_wire_names; + dict new_cell_names; + + for (auto wire : module->selected_wires()) + if (wire->port_id == 0) { + seed = mkhash_xorshift(seed); + new_wire_names[wire] = stringf("$_%u_", seed); + } + + for (auto cell : module->selected_cells()) { + seed = mkhash_xorshift(seed); + new_cell_names[cell] = stringf("$_%u_", seed); + } + + for (auto &it : new_wire_names) + module->rename(it.first, it.second); + + for (auto &it : new_cell_names) + module->rename(it.first, it.second); + } + } + else { if (argidx+2 != args.size()) log_cmd_error("Invalid number of arguments!\n"); diff --git a/tests/various/rename_scramble_name.ys b/tests/various/rename_scramble_name.ys new file mode 100644 index 000000000..9a36d0922 --- /dev/null +++ b/tests/various/rename_scramble_name.ys @@ -0,0 +1,31 @@ +read_verilog < Date: Mon, 8 Aug 2022 20:30:50 +0200 Subject: support file locations containing spaces --- passes/sat/qbfsat.cc | 2 +- passes/techmap/abc.cc | 10 +++++----- passes/techmap/abc9_exe.cc | 6 +++--- tests/arch/ice40/.gitignore | 1 + tests/gen-tests-makefile.sh | 2 +- tests/tools/autotest.sh | 16 ++++++++-------- 6 files changed, 19 insertions(+), 18 deletions(-) diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc index 864d6f05d..1302b3383 100644 --- a/passes/sat/qbfsat.cc +++ b/passes/sat/qbfsat.cc @@ -216,7 +216,7 @@ QbfSolutionType call_qbf_solver(RTLIL::Module *mod, const QbfSolveOptions &opt, QbfSolutionType ret; const std::string yosys_smtbmc_exe = proc_self_dirname() + "yosys-smtbmc"; const std::string smtbmc_warning = "z3: WARNING:"; - const std::string smtbmc_cmd = stringf("%s -s %s %s -t 1 -g --binary %s %s/problem%d.smt2 2>&1", + const std::string smtbmc_cmd = stringf("\"%s\" -s %s %s -t 1 -g --binary %s %s/problem%d.smt2 2>&1", yosys_smtbmc_exe.c_str(), opt.get_solver_name().c_str(), (opt.timeout != 0? stringf("--timeout %d", opt.timeout) : "").c_str(), (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file : "").c_str(), diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 0b9c327c0..656c36b84 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -789,15 +789,15 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin log_header(design, "Extracting gate netlist of module `%s' to `%s/input.blif'..\n", module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str()); - std::string abc_script = stringf("read_blif %s/input.blif; ", tempdir_name.c_str()); + 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()); + abc_script += stringf("read_lib -w \"%s\"; ", liberty_file.c_str()); for (std::string liberty_file : genlib_files) - abc_script += stringf("read_library %s; ", liberty_file.c_str()); + abc_script += stringf("read_library \"%s\"; ", liberty_file.c_str()); if (!constr_file.empty()) - abc_script += stringf("read_constr -v %s; ", constr_file.c_str()); + abc_script += stringf("read_constr -v \"%s\"; ", constr_file.c_str()); } else if (!lut_costs.empty()) abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); @@ -1085,7 +1085,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin fclose(f); } - buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); + buffer = stringf("\"%s\" -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); #ifndef YOSYS_LINK_ABC diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc index 7dc0a364b..2f46c89f4 100644 --- a/passes/techmap/abc9_exe.cc +++ b/passes/techmap/abc9_exe.cc @@ -175,12 +175,12 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe if (!lut_costs.empty()) abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); else if (!lut_file.empty()) - abc9_script += stringf("read_lut %s; ", lut_file.c_str()); + abc9_script += stringf("read_lut \"%s\"; ", lut_file.c_str()); else log_abort(); log_assert(!box_file.empty()); - abc9_script += stringf("read_box %s; ", box_file.c_str()); + abc9_script += stringf("read_box \"%s\"; ", box_file.c_str()); abc9_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str()); if (!script_file.empty()) { @@ -264,7 +264,7 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe fclose(f); } - buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); + buffer = stringf("\"%s\" -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); #ifndef YOSYS_LINK_ABC diff --git a/tests/arch/ice40/.gitignore b/tests/arch/ice40/.gitignore index 9a71dca69..54f908bdb 100644 --- a/tests/arch/ice40/.gitignore +++ b/tests/arch/ice40/.gitignore @@ -1,4 +1,5 @@ *.log +*.json /run-test.mk +*_synth.v +*_testbench diff --git a/tests/gen-tests-makefile.sh b/tests/gen-tests-makefile.sh index ab8fb7013..cde9ab1b9 100755 --- a/tests/gen-tests-makefile.sh +++ b/tests/gen-tests-makefile.sh @@ -17,7 +17,7 @@ generate_target() { generate_ys_test() { ys_file=$1 yosys_args=${2:-} - generate_target "$ys_file" "$YOSYS_BASEDIR/yosys -ql ${ys_file%.*}.log $yosys_args $ys_file" + generate_target "$ys_file" "\"$YOSYS_BASEDIR/yosys\" -ql ${ys_file%.*}.log $yosys_args $ys_file" } # $ generate_bash_test bash_file diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index e4aef9917..f96eb8d71 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -libs="" +libs=() genvcd=false use_xsim=false use_modelsim=false @@ -15,7 +15,7 @@ xinclude_opts="" minclude_opts="" scriptfiles="" scriptopt="" -toolsdir="$(cd $(dirname $0); pwd)" +toolsdir="$(cd "$(dirname "$0")"; pwd)" warn_iverilog_git=false # The following are used in verilog to firrtl regression tests. # Typically these will be passed as environment variables: @@ -25,8 +25,8 @@ firrtl2verilog="" xfirrtl="../xfirrtl" abcprog="$toolsdir/../../yosys-abc" -if [ ! -f $toolsdir/cmp_tbdata -o $toolsdir/cmp_tbdata.c -nt $toolsdir/cmp_tbdata ]; then - ( set -ex; ${CC:-gcc} -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1 +if [ ! -f "$toolsdir/cmp_tbdata" -o "$toolsdir/cmp_tbdata.c" -nt "$toolsdir/cmp_tbdata" ]; then + ( set -ex; ${CC:-gcc} -Wall -o "$toolsdir/cmp_tbdata" "$toolsdir/cmp_tbdata.c"; ) || exit 1 fi while getopts xmGl:wkjvref:s:p:n:S:I:A:-: opt; do @@ -38,7 +38,7 @@ while getopts xmGl:wkjvref:s:p:n:S:I:A:-: opt; do G) warn_iverilog_git=true ;; l) - libs="$libs $(cd $(dirname $OPTARG); pwd)/$(basename $OPTARG)";; + libs+=("$(cd "$(dirname "$OPTARG")"; pwd)/$(basename "$OPTARG")");; w) genvcd=true ;; k) @@ -162,7 +162,7 @@ do cp ../${bn}_tb.v ${bn}_tb.v fi if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi - compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.${refext} $libs \ + compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.${refext} "${libs[@]}" \ "$toolsdir"/../../techlibs/common/simlib.v \ "$toolsdir"/../../techlibs/common/simcells.v if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi @@ -171,11 +171,11 @@ do test_passes() { "$toolsdir"/../../yosys -b "verilog $backend_opts" -o ${bn}_syn${test_count}.v "$@" compile_and_run ${bn}_tb_syn${test_count} ${bn}_out_syn${test_count} \ - ${bn}_tb.v ${bn}_syn${test_count}.v $libs \ + ${bn}_tb.v ${bn}_syn${test_count}.v "${libs[@]}" \ "$toolsdir"/../../techlibs/common/simlib.v \ "$toolsdir"/../../techlibs/common/simcells.v if $genvcd; then mv testbench.vcd ${bn}_syn${test_count}.vcd; fi - $toolsdir/cmp_tbdata ${bn}_out_ref ${bn}_out_syn${test_count} + "$toolsdir/cmp_tbdata" ${bn}_out_ref ${bn}_out_syn${test_count} test_count=$(( test_count + 1 )) } -- cgit v1.2.3 From d2b4246a6d5b7b0a30ea7df23a6d06f0846b0304 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 9 Aug 2022 00:19:53 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b794e9886..be162ea72 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.20+1 +YOSYS_VER := 0.20+6 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From 99f1c71582bce51aab25b3a50b15eec002545ef4 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 9 Aug 2022 12:45:32 +0200 Subject: properly encode string in rtlil --- backends/rtlil/rtlil_backend.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/rtlil/rtlil_backend.cc b/backends/rtlil/rtlil_backend.cc index 1b11de5ec..b5163aefe 100644 --- a/backends/rtlil/rtlil_backend.cc +++ b/backends/rtlil/rtlil_backend.cc @@ -75,7 +75,7 @@ void RTLIL_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int wi else if (str[i] == '\t') f << stringf("\\t"); else if (str[i] < 32) - f << stringf("\\%03o", str[i]); + f << stringf("\\%03o", (unsigned char)str[i]); else if (str[i] == '"') f << stringf("\\\""); else if (str[i] == '\\') -- cgit v1.2.3 From 4444d5cf680e40ca287c4f30c9a4b41a443d9c4f Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 9 Aug 2022 12:54:48 +0200 Subject: Switched to utf-8 in smtio.py --- backends/smt2/smtio.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py index 91efc13a3..3ba43825c 100644 --- a/backends/smt2/smtio.py +++ b/backends/smt2/smtio.py @@ -337,7 +337,7 @@ class SmtIo: def p_thread_main(self): while True: - data = self.p.stdout.readline().decode("ascii") + data = self.p.stdout.readline().decode("utf-8") if data == "": break self.p_queue.put(data) self.p_queue.put("") @@ -359,7 +359,7 @@ class SmtIo: def p_write(self, data, flush): assert self.p is not None - self.p.stdin.write(bytes(data, "ascii")) + self.p.stdin.write(bytes(data, "utf-8")) if flush: self.p.stdin.flush() def p_read(self): -- cgit v1.2.3 From 8fab6ec023dc0e343ff4dbe08d9bafee7f871306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 22 Jul 2022 17:51:16 +0200 Subject: nexus: Fix BRAM mapping. --- techlibs/nexus/brams_map.v | 74 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/techlibs/nexus/brams_map.v b/techlibs/nexus/brams_map.v index 3cada2414..17306cded 100644 --- a/techlibs/nexus/brams_map.v +++ b/techlibs/nexus/brams_map.v @@ -32,10 +32,10 @@ output [PORT_B_WIDTH-1:0] PORT_B_RD_DATA; function [319:0] init_slice; input integer idx; - integer i, j; + integer i; init_slice = 0; - for (i = 0; i < 16; i = i + 1) begin - init_slice[i*20+:18] = INIT[(idx * 16 + i) * 18+:18]; + for (i = 0; i < 32; i = i + 1) begin + init_slice[i*10+:9] = INIT[(idx * 32 + i) * 9+:9]; end endfunction @@ -43,8 +43,28 @@ wire [17:0] DOA; wire [17:0] DOB; wire [17:0] DIA = PORT_A_WR_DATA; wire [17:0] DIB = PORT_B_WR_DATA; -wire [13:0] ADA = PORT_A_WIDTH == 18 ? {PORT_A_ADDR[13:2], PORT_A_WR_BE} : PORT_A_ADDR; -wire [13:0] ADB = PORT_B_WIDTH == 18 ? {PORT_B_ADDR[13:2], PORT_B_WR_BE} : PORT_B_ADDR; +wire [13:0] ADA; +wire [13:0] ADB; + +generate + +case(PORT_A_WIDTH) +1: assign ADA = PORT_A_ADDR; +2: assign ADA = {PORT_A_ADDR[13:1], 1'b1}; +4: assign ADA = {PORT_A_ADDR[13:2], 2'b11}; +9: assign ADA = {PORT_A_ADDR[13:3], 3'b111}; +18: assign ADA = {PORT_A_ADDR[13:4], 2'b11, PORT_A_WR_BE}; +endcase + +case(PORT_B_WIDTH) +1: assign ADB = PORT_B_ADDR; +2: assign ADB = {PORT_B_ADDR[13:1], 1'b1}; +4: assign ADB = {PORT_B_ADDR[13:2], 2'b11}; +9: assign ADB = {PORT_B_ADDR[13:3], 3'b111}; +18: assign ADB = {PORT_B_ADDR[13:4], 2'b11, PORT_B_WR_BE}; +endcase + +endgenerate assign PORT_A_RD_DATA = DOA; assign PORT_B_RD_DATA = DOB; @@ -122,8 +142,8 @@ DP16K #( .RESETMODE_B(PORT_B_OPTION_RESETMODE), .ASYNC_RST_RELEASE_A(PORT_A_OPTION_RESETMODE), .ASYNC_RST_RELEASE_B(PORT_B_OPTION_RESETMODE), - .CSDECODE_A("000"), - .CSDECODE_B("000"), + .CSDECODE_A("111"), + .CSDECODE_B("111"), .GSR("DISABLED"), ) _TECHMAP_REPLACE_ ( .CLKA(PORT_A_CLK), @@ -176,10 +196,10 @@ input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA; function [319:0] init_slice; input integer idx; - integer i, j; + integer i; init_slice = 0; - for (i = 0; i < 16; i = i + 1) begin - init_slice[i*20+:18] = INIT[(idx * 16 + i) * 18+:18]; + for (i = 0; i < 32; i = i + 1) begin + init_slice[i*10+:9] = INIT[(idx * 32 + i) * 9+:9]; end endfunction @@ -188,11 +208,29 @@ wire [35:0] DO; assign PORT_R_RD_DATA = DO; -wire [13:0] ADW = PORT_W_WIDTH == 36 ? {PORT_W_ADDR[13:4], PORT_W_WR_EN} : - (PORT_W_WIDTH == 18 ? {PORT_W_ADDR[13:2], PORT_W_WR_EN} : PORT_W_ADDR); +wire [13:0] ADW; +wire [13:0] ADR; generate +case (PORT_W_WIDTH) +1: assign ADW = PORT_W_ADDR; +2: assign ADW = {PORT_W_ADDR[13:1], 1'b1}; +4: assign ADW = {PORT_W_ADDR[13:2], 2'b11}; +9: assign ADW = {PORT_W_ADDR[13:3], 3'b111}; +18: assign ADW = {PORT_W_ADDR[13:4], 2'b11, PORT_W_WR_EN}; +36: assign ADW = {PORT_W_ADDR[13:5], 1'b1, PORT_W_WR_EN}; +endcase + +case (PORT_R_WIDTH) +1: assign ADR = PORT_R_ADDR; +2: assign ADR = {PORT_R_ADDR[13:1], 1'b1}; +4: assign ADR = {PORT_R_ADDR[13:2], 2'b11}; +9: assign ADR = {PORT_R_ADDR[13:3], 3'b111}; +18: assign ADR = {PORT_R_ADDR[13:4], 4'b1111}; +36: assign ADR = {PORT_R_ADDR[13:5], 5'b11111}; +endcase + if (OPTION_SAME_CLOCK) begin PDPSC16K #( @@ -265,8 +303,8 @@ PDPSC16K #( .OUTREG("BYPASSED"), .RESETMODE(PORT_R_OPTION_RESETMODE), .ASYNC_RST_RELEASE(PORT_R_OPTION_RESETMODE), - .CSDECODE_W("000"), - .CSDECODE_R("000"), + .CSDECODE_W("111"), + .CSDECODE_R("111"), .ECC("DISABLED"), .GSR("DISABLED"), ) _TECHMAP_REPLACE_ ( @@ -280,7 +318,7 @@ PDPSC16K #( .CER(PORT_R_CLK_EN), .RST(PORT_R_OPTION_RESETMODE == "SYNC" ? PORT_R_RD_SRST : PORT_R_RD_ARST), .CSR(3'b111), - .ADR(PORT_R_ADDR), + .ADR(ADR), .DO(DO), ); @@ -356,8 +394,8 @@ PDP16K #( .OUTREG("BYPASSED"), .RESETMODE(PORT_R_OPTION_RESETMODE), .ASYNC_RST_RELEASE(PORT_R_OPTION_RESETMODE), - .CSDECODE_W("000"), - .CSDECODE_R("000"), + .CSDECODE_W("111"), + .CSDECODE_R("111"), .ECC("DISABLED"), .GSR("DISABLED"), ) _TECHMAP_REPLACE_ ( @@ -371,7 +409,7 @@ PDP16K #( .CER(PORT_R_CLK_EN), .RST(PORT_R_OPTION_RESETMODE == "SYNC" ? PORT_R_RD_SRST : PORT_R_RD_ARST), .CSR(3'b111), - .ADR(PORT_R_ADDR), + .ADR(ADR), .DO(DO), ); -- cgit v1.2.3 From 035d99f3a82812669b801fb27aeee30876d61049 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 10 Aug 2022 00:16:23 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index be162ea72..1759ea182 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.20+6 +YOSYS_VER := 0.20+11 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From 8c05f14b58fd0d4d6409342a172cd73202e507ae Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Wed, 18 May 2022 14:53:46 -0400 Subject: Order ports with default assignments first Although the current style is allowed by the standard, Icarus verilog doesn't parse default assignments using an implicit net type: techlibs/ice40/cells_sim.v:305: syntax error techlibs/ice40/cells_sim.v:1: Errors in port declarations. Fix this by making sure that ports with default assignments first on their line. Fixes: 46d3f03d2 ("Add default assignments to other SB_* simulation models") Signed-off-by: Sean Anderson --- techlibs/ice40/cells_sim.v | 48 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 2e1c6807a..52e8e2e3a 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -302,7 +302,9 @@ endmodule (* abc9_flop, lib_whitebox *) module SB_DFFE ( output reg Q, - input C, E `ICE40_DEFAULT_ASSIGNMENT_1, D + input C, + input E `ICE40_DEFAULT_ASSIGNMENT_1, + input D ); `SB_DFF_INIT @@ -589,7 +591,10 @@ endmodule (* abc9_flop, lib_whitebox *) module SB_DFFESR ( output reg Q, - input C, E `ICE40_DEFAULT_ASSIGNMENT_1, R, D + input C, + input E `ICE40_DEFAULT_ASSIGNMENT_1, + input R, + input D ); `SB_DFF_INIT @@ -647,7 +652,10 @@ endmodule (* abc9_box, lib_whitebox *) module SB_DFFER ( output reg Q, - input C, E `ICE40_DEFAULT_ASSIGNMENT_1, R, D + input C, + input E `ICE40_DEFAULT_ASSIGNMENT_1, + input R, + input D ); `SB_DFF_INIT @@ -724,7 +732,10 @@ endmodule (* abc9_flop, lib_whitebox *) module SB_DFFESS ( output reg Q, - input C, E `ICE40_DEFAULT_ASSIGNMENT_1, S, D + input C, + input E `ICE40_DEFAULT_ASSIGNMENT_1, + input S, + input D ); `SB_DFF_INIT @@ -782,7 +793,10 @@ endmodule (* abc9_box, lib_whitebox *) module SB_DFFES ( output reg Q, - input C, E `ICE40_DEFAULT_ASSIGNMENT_1, S, D + input C, + input E `ICE40_DEFAULT_ASSIGNMENT_1, + input S, + input D ); `SB_DFF_INIT @@ -899,7 +913,9 @@ endmodule (* abc9_flop, lib_whitebox *) module SB_DFFNE ( output reg Q, - input C, E `ICE40_DEFAULT_ASSIGNMENT_1, D + input C, + input E `ICE40_DEFAULT_ASSIGNMENT_1, + input D ); `SB_DFF_INIT @@ -1186,7 +1202,10 @@ endmodule (* abc9_flop, lib_whitebox *) module SB_DFFNESR ( output reg Q, - input C, E `ICE40_DEFAULT_ASSIGNMENT_1, R, D + input C, + input E `ICE40_DEFAULT_ASSIGNMENT_1, + input R, + input D ); `SB_DFF_INIT @@ -1244,7 +1263,10 @@ endmodule (* abc9_box, lib_whitebox *) module SB_DFFNER ( output reg Q, - input C, E `ICE40_DEFAULT_ASSIGNMENT_1, R, D + input C, + input E `ICE40_DEFAULT_ASSIGNMENT_1, + input R, + input D ); `SB_DFF_INIT @@ -1321,7 +1343,10 @@ endmodule (* abc9_flop, lib_whitebox *) module SB_DFFNESS ( output reg Q, - input C, E `ICE40_DEFAULT_ASSIGNMENT_1, S, D + input C, + input E `ICE40_DEFAULT_ASSIGNMENT_1, + input S, + input D ); `SB_DFF_INIT @@ -1379,7 +1404,10 @@ endmodule (* abc9_box, lib_whitebox *) module SB_DFFNES ( output reg Q, - input C, E `ICE40_DEFAULT_ASSIGNMENT_1, S, D + input C, + input E `ICE40_DEFAULT_ASSIGNMENT_1, + input S, + input D ); `SB_DFF_INIT -- cgit v1.2.3 From 545a3417c81d454071b8d39b6ac88258ceb891a3 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 10 Aug 2022 11:38:50 +0200 Subject: resetall does not affect text defines, but undefineall does --- frontends/verilog/preproc.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index 883531e78..9781a22d9 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -961,6 +961,10 @@ frontend_verilog_preproc(std::istream &f, } if (tok == "`resetall") { + continue; + } + + if (tok == "`undefineall" && sv_mode) { defines.clear(); global_defines_cache.clear(); continue; -- cgit v1.2.3 From b76c72056b37d8f2b84948cbdc302b149577e648 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 10 Aug 2022 13:28:19 +0200 Subject: set default_nettype to wire for resetall --- frontends/verilog/preproc.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index 9781a22d9..e33b0a2c3 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -961,6 +961,7 @@ frontend_verilog_preproc(std::istream &f, } if (tok == "`resetall") { + default_nettype_wire = true; continue; } -- cgit v1.2.3 From 91010449ff2a66f89c2a8f9718ae320d3e899c41 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 11 Aug 2022 00:19:11 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1759ea182..bd8e4d35d 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.20+11 +YOSYS_VER := 0.20+17 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From 59facfa98c82ad019980ecbc92d74e01e0bc3e7a Mon Sep 17 00:00:00 2001 From: Lofty Date: Thu, 28 Jul 2022 13:05:34 +0100 Subject: stat: add option for machine-readable json output --- passes/cmds/stat.cc | 147 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 109 insertions(+), 38 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index c858c8631..a4984597d 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -17,10 +17,13 @@ * */ +#include + #include "kernel/yosys.h" #include "kernel/celltypes.h" #include "passes/techmap/libparse.h" #include "kernel/cost.h" +#include "libs/json11/json11.hpp" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -32,14 +35,14 @@ struct statdata_t #define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area) - #define X(_name) int _name; + #define X(_name) unsigned int _name; STAT_INT_MEMBERS #undef X double area; string tech; std::map techinfo; - std::map num_cells_by_type; + std::map num_cells_by_type; std::set unknown_cell_area; statdata_t operator+(const statdata_t &other) const @@ -53,7 +56,7 @@ struct statdata_t return sum; } - statdata_t operator*(int other) const + statdata_t operator*(unsigned int other) const { statdata_t sum = *this; #define X(_name) sum._name *= other; @@ -148,17 +151,17 @@ struct statdata_t void log_data(RTLIL::IdString mod_name, bool top_mod) { - log(" Number of wires: %6d\n", num_wires); - log(" Number of wire bits: %6d\n", num_wire_bits); - log(" Number of public wires: %6d\n", num_pub_wires); - log(" Number of public wire bits: %6d\n", num_pub_wire_bits); - log(" Number of memories: %6d\n", num_memories); - log(" Number of memory bits: %6d\n", num_memory_bits); - log(" Number of processes: %6d\n", num_processes); - log(" Number of cells: %6d\n", num_cells); + log(" Number of wires: %6u\n", num_wires); + log(" Number of wire bits: %6u\n", num_wire_bits); + log(" Number of public wires: %6u\n", num_pub_wires); + log(" Number of public wire bits: %6u\n", num_pub_wire_bits); + log(" Number of memories: %6u\n", num_memories); + log(" Number of memory bits: %6u\n", num_memory_bits); + log(" Number of processes: %6u\n", num_processes); + log(" Number of cells: %6u\n", num_cells); for (auto &it : num_cells_by_type) if (it.second) - log(" %-26s %6d\n", log_id(it.first), it.second); + log(" %-26s %6u\n", log_id(it.first), it.second); if (!unknown_cell_area.empty()) { log("\n"); @@ -173,13 +176,13 @@ struct statdata_t if (tech == "xilinx") { - int lut6_cnt = num_cells_by_type[ID(LUT6)]; - int lut5_cnt = num_cells_by_type[ID(LUT5)]; - int lut4_cnt = num_cells_by_type[ID(LUT4)]; - int lut3_cnt = num_cells_by_type[ID(LUT3)]; - int lut2_cnt = num_cells_by_type[ID(LUT2)]; - int lut1_cnt = num_cells_by_type[ID(LUT1)]; - int lc_cnt = 0; + unsigned int lut6_cnt = num_cells_by_type[ID(LUT6)]; + unsigned int lut5_cnt = num_cells_by_type[ID(LUT5)]; + unsigned int lut4_cnt = num_cells_by_type[ID(LUT4)]; + unsigned int lut3_cnt = num_cells_by_type[ID(LUT3)]; + unsigned int lut2_cnt = num_cells_by_type[ID(LUT2)]; + unsigned int lut1_cnt = num_cells_by_type[ID(LUT1)]; + unsigned int lc_cnt = 0; lc_cnt += lut6_cnt; @@ -221,12 +224,12 @@ struct statdata_t lc_cnt += (lut2_cnt + lut1_cnt + 1) / 2; log("\n"); - log(" Estimated number of LCs: %10d\n", lc_cnt); + log(" Estimated number of LCs: %10u\n", lc_cnt); } if (tech == "cmos") { - int tran_cnt = 0; + unsigned int tran_cnt = 0; bool tran_cnt_exact = true; auto &gate_costs = CellCosts::cmos_gate_cost(); @@ -243,20 +246,48 @@ struct statdata_t } log("\n"); - log(" Estimated number of transistors: %10d%s\n", tran_cnt, tran_cnt_exact ? "" : "+"); + log(" Estimated number of transistors: %10u%s\n", tran_cnt, tran_cnt_exact ? "" : "+"); } } + + void log_data_json(const char *mod_name, bool first_module) + { + if (!first_module) + log(",\n"); + log(" %s: {\n", json11::Json(mod_name).dump().c_str()); + log(" \"num_wires\": %u,\n", num_wires); + log(" \"num_wire_bits\": %u,\n", num_wire_bits); + log(" \"num_pub_wires\": %u,\n", num_pub_wires); + log(" \"num_pub_wire_bits\": %u,\n", num_pub_wire_bits); + log(" \"num_memories\": %u,\n", num_memories); + log(" \"num_memory_bits\": %u,\n", num_memory_bits); + log(" \"num_processes\": %u,\n", num_processes); + log(" \"num_cells\": %u,\n", num_cells); + log(" \"num_cells_by_type\": {\n"); + bool first_line = true; + for (auto &it : num_cells_by_type) + if (it.second) { + if (!first_line) + log(",\n"); + log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); + first_line = false; + } + log("\n"); + log(" }\n"); + log(" }"); + } }; -statdata_t hierarchy_worker(std::map &mod_stat, RTLIL::IdString mod, int level) +statdata_t hierarchy_worker(std::map &mod_stat, RTLIL::IdString mod, int level, bool quiet = false) { statdata_t mod_data = mod_stat.at(mod); - std::map num_cells_by_type; + std::map num_cells_by_type; num_cells_by_type.swap(mod_data.num_cells_by_type); for (auto &it : num_cells_by_type) if (mod_stat.count(it.first) > 0) { - log(" %*s%-*s %6d\n", 2*level, "", 26-2*level, log_id(it.first), it.second); + if (!quiet) + log(" %*s%-*s %6u\n", 2*level, "", 26-2*level, log_id(it.first), it.second); mod_data = mod_data + hierarchy_worker(mod_stat, it.first, level+1) * it.second; mod_data.num_cells -= it.second; } else { @@ -314,12 +345,16 @@ struct StatPass : public Pass { log(" annotate internal cell types with their word width.\n"); log(" e.g. $add_8 for an 8 bit wide $add cell.\n"); log("\n"); + log(" -json\n"); + log(" output the statistics in a machine-readable JSON format.\n"); + log(" this is output to the console; use \"tee\" to output to a file.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { log_header(design, "Printing statistics.\n"); - bool width_mode = false; + bool width_mode = false, json_mode = false; RTLIL::Module *top_mod = nullptr; std::map mod_stat; dict cell_area; @@ -348,13 +383,27 @@ struct StatPass : public Pass { top_mod = design->module(RTLIL::escape_id(args[++argidx])); continue; } + if (args[argidx] == "-json") { + json_mode = true; + continue; + } break; } extra_args(args, argidx, design); - if (techname != "" && techname != "xilinx" && techname != "cmos") + if (techname != "" && techname != "xilinx" && techname != "cmos" && !json_mode) log_cmd_error("Unsupported technology: '%s'\n", techname.c_str()); + if (json_mode) { + log("{\n"); + log(" \"creator\": %s,\n", json11::Json(yosys_version_str).dump().c_str()); + std::stringstream invocation; + std::copy(args.begin(), args.end(), std::ostream_iterator(invocation, " ")); + log(" \"invocation\": %s,\n", json11::Json(invocation.str()).dump().c_str()); + log(" \"modules\": {\n"); + } + + bool first_module = true; for (auto mod : design->selected_modules()) { if (!top_mod && design->full_selection()) @@ -364,23 +413,40 @@ struct StatPass : public Pass { statdata_t data(design, mod, width_mode, cell_area, techname); mod_stat[mod->name] = data; + if (json_mode) { + data.log_data_json(mod->name.c_str(), first_module); + first_module = false; + } else { + log("\n"); + log("=== %s%s ===\n", log_id(mod->name), design->selected_whole_module(mod->name) ? "" : " (partially selected)"); + log("\n"); + data.log_data(mod->name, false); + } + } + + if (json_mode) { log("\n"); - log("=== %s%s ===\n", log_id(mod->name), design->selected_whole_module(mod->name) ? "" : " (partially selected)"); - log("\n"); - data.log_data(mod->name, false); + log(" },\n"); } - if (top_mod != nullptr && GetSize(mod_stat) > 1) + if (top_mod != nullptr) { - log("\n"); - log("=== design hierarchy ===\n"); - log("\n"); + if (!json_mode && GetSize(mod_stat) > 1) { + log("\n"); + log("=== design hierarchy ===\n"); + log("\n"); + log(" %-28s %6d\n", log_id(top_mod->name), 1); + } - log(" %-28s %6d\n", log_id(top_mod->name), 1); - statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0); + statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0, /*quiet=*/json_mode); + + if (json_mode) + data.log_data_json("design", true); + else if (GetSize(mod_stat) > 1) { + log("\n"); + data.log_data(top_mod->name, true); + } - log("\n"); - data.log_data(top_mod->name, true); design->scratchpad_set_int("stat.num_wires", data.num_wires); design->scratchpad_set_int("stat.num_wire_bits", data.num_wire_bits); design->scratchpad_set_int("stat.num_pub_wires", data.num_pub_wires); @@ -392,6 +458,11 @@ struct StatPass : public Pass { design->scratchpad_set_int("stat.area", data.area); } + if (json_mode) { + log("\n"); + log("}\n"); + } + log("\n"); } } StatPass; -- cgit v1.2.3 From c26b2bf543a226e65a3fb07040bb278d668accf2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 12 Aug 2022 00:16:29 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index bd8e4d35d..b3a466a5e 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.20+17 +YOSYS_VER := 0.20+22 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From c0063288d699f4f3edf5e0ff6ee1bd5cfa9ac884 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Thu, 21 Jul 2022 14:22:15 +0200 Subject: Add the $anyinit cell and the formalff pass These can be used to protect undefined flip-flop initialization values from optimizations that are not sound for formal verification and can help mapping all solver-provided values in witness traces for flows that use different backends simultaneously. --- CHANGELOG | 6 ++ kernel/celltypes.h | 6 ++ kernel/ff.cc | 19 ++++- kernel/ff.h | 8 +- kernel/rtlil.cc | 17 ++++ kernel/rtlil.h | 2 + kernel/satgen.cc | 2 +- manual/CHAPTER_CellLib.tex | 2 +- passes/cmds/show.cc | 1 + passes/fsm/fsm_detect.cc | 1 + passes/hierarchy/submod.cc | 1 + passes/opt/opt_clean.cc | 2 + passes/sat/Makefile.inc | 1 + passes/sat/formalff.cc | 192 +++++++++++++++++++++++++++++++++++++++++++++ passes/sat/sim.cc | 2 +- techlibs/common/simlib.v | 17 ++++ 16 files changed, 271 insertions(+), 8 deletions(-) create mode 100644 passes/sat/formalff.cc diff --git a/CHANGELOG b/CHANGELOG index 434872248..199d6a61a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,12 @@ List of major changes and improvements between releases Yosys 0.20 .. Yosys 0.20-dev -------------------------- + * New commands and options + - Added "formalff" pass - transforms FFs for formal verification + + * Formal Verification + - Added $anyinit cell to directly represent FFs with an unconstrained + initialization value. These can be generated by the new formalff pass. Yosys 0.19 .. Yosys 0.20 -------------------------- diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 7e9cfb38d..d62ba1506 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -51,6 +51,7 @@ struct CellTypes setup_internals(); setup_internals_mem(); + setup_internals_anyinit(); setup_stdcells(); setup_stdcells_mem(); } @@ -155,6 +156,11 @@ struct CellTypes setup_type(ID($dlatchsr), {ID::EN, ID::SET, ID::CLR, ID::D}, {ID::Q}); } + void setup_internals_anyinit() + { + setup_type(ID($anyinit), {ID::D}, {ID::Q}); + } + void setup_internals_mem() { setup_internals_ff(); diff --git a/kernel/ff.cc b/kernel/ff.cc index b0f1a924f..697ba7342 100644 --- a/kernel/ff.cc +++ b/kernel/ff.cc @@ -33,10 +33,14 @@ FfData::FfData(FfInitVals *initvals, Cell *cell_) : FfData(cell_->module, initva std::string type_str = cell->type.str(); - if (cell->type.in(ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) { - if (cell->type == ID($ff)) { + if (cell->type.in(ID($anyinit), ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) { + if (cell->type.in(ID($anyinit), ID($ff))) { has_gclk = true; sig_d = cell->getPort(ID::D); + if (cell->type == ID($anyinit)) { + is_anyinit = true; + log_assert(val_init.is_fully_undef()); + } } else if (cell->type == ID($sr)) { // No data input at all. } else if (cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr))) { @@ -274,6 +278,7 @@ FfData FfData::slice(const std::vector &bits) { res.has_sr = has_sr; res.ce_over_srst = ce_over_srst; res.is_fine = is_fine; + res.is_anyinit = is_anyinit; res.pol_clk = pol_clk; res.pol_ce = pol_ce; res.pol_aload = pol_aload; @@ -542,7 +547,7 @@ Cell *FfData::emit() { return nullptr; } } - if (initvals) + if (initvals && !is_anyinit) initvals->set_init(sig_q, val_init); if (!is_fine) { if (has_gclk) { @@ -552,7 +557,12 @@ Cell *FfData::emit() { log_assert(!has_arst); log_assert(!has_srst); log_assert(!has_sr); - cell = module->addFf(name, sig_d, sig_q); + if (is_anyinit) { + cell = module->addAnyinit(name, sig_d, sig_q); + log_assert(val_init.is_fully_undef()); + } else { + cell = module->addFf(name, sig_d, sig_q); + } } else if (!has_aload && !has_clk) { log_assert(has_sr); cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr); @@ -603,6 +613,7 @@ Cell *FfData::emit() { log_assert(!has_arst); log_assert(!has_srst); log_assert(!has_sr); + log_assert(!is_anyinit); cell = module->addFfGate(name, sig_d, sig_q); } else if (!has_aload && !has_clk) { log_assert(has_sr); diff --git a/kernel/ff.h b/kernel/ff.h index 41721b4a1..e684d3c43 100644 --- a/kernel/ff.h +++ b/kernel/ff.h @@ -28,7 +28,10 @@ YOSYS_NAMESPACE_BEGIN // Describes a flip-flop or a latch. // // If has_gclk, this is a formal verification FF with implicit global clock: -// Q is simply previous cycle's D. +// Q is simply previous cycle's D. Additionally if is_anyinit is true, this is +// an $anyinit cell which always has an undefined initialization value. Note +// that $anyinit is not considered to be among the FF celltypes, so a pass has +// to explicitly opt-in to process $anyinit cells with FfData. // // Otherwise, the FF/latch can have any number of features selected by has_* // attributes that determine Q's value (in order of decreasing priority): @@ -126,6 +129,8 @@ struct FfData { // True if this FF is a fine cell, false if it is a coarse cell. // If true, width must be 1. bool is_fine; + // True if this FF is an $anyinit cell. Depends on has_gclk. + bool is_anyinit; // Polarities, corresponding to sig_*. True means active-high, false // means active-low. bool pol_clk; @@ -156,6 +161,7 @@ struct FfData { has_sr = false; ce_over_srst = false; is_fine = false; + is_anyinit = false; pol_clk = false; pol_aload = false; pol_ce = false; diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index b274bba78..5211c3b3f 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -1632,6 +1632,13 @@ namespace { return; } + if (cell->type.in(ID($anyinit))) { + port(ID::D, param(ID::WIDTH)); + port(ID::Q, param(ID::WIDTH)); + check_expected(); + return; + } + if (cell->type == ID($equiv)) { port(ID::A, 1); port(ID::B, 1); @@ -3120,6 +3127,16 @@ RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, const RTLIL::S return cell; } +RTLIL::Cell* RTLIL::Module::addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src) +{ + RTLIL::Cell *cell = addCell(name, ID($anyinit)); + cell->parameters[ID::WIDTH] = sig_q.size(); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->set_src_attribute(src); + return cell; +} + RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width, const std::string &src) { RTLIL::SigSpec sig = addWire(NEW_ID, width); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index db175d7e9..27ffdff1f 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1375,6 +1375,8 @@ public: RTLIL::Cell* addDlatchsrGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); + RTLIL::Cell* addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = ""); + // The methods without the add* prefix create a cell and an output signal. They return the newly created output signal. RTLIL::SigSpec Not (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); diff --git a/kernel/satgen.cc b/kernel/satgen.cc index 9c40ec66d..05eeca76e 100644 --- a/kernel/satgen.cc +++ b/kernel/satgen.cc @@ -1176,7 +1176,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep) return true; } - if (timestep > 0 && RTLIL::builtin_ff_cell_types().count(cell->type)) + if (timestep > 0 && (RTLIL::builtin_ff_cell_types().count(cell->type) || cell->type == ID($anyinit))) { FfData ff(nullptr, cell); diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex index 3c9fb31cc..86b1f6a9a 100644 --- a/manual/CHAPTER_CellLib.tex +++ b/manual/CHAPTER_CellLib.tex @@ -603,7 +603,7 @@ Add information about {\tt \$specify2}, {\tt \$specify3}, and {\tt \$specrule} c \begin{fixme} Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$live}, {\tt \$fair}, {\tt \$cover}, {\tt \$equiv}, -{\tt \$initstate}, {\tt \$anyconst}, {\tt \$anyseq}, {\tt \$allconst}, {\tt \$allseq} cells. +{\tt \$initstate}, {\tt \$anyconst}, {\tt \$anyseq}, {\tt \$anyinit}, {\tt \$allconst}, {\tt \$allseq} cells. \end{fixme} \begin{fixme} diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc index 43deba47b..4d5605932 100644 --- a/passes/cmds/show.cc +++ b/passes/cmds/show.cc @@ -574,6 +574,7 @@ struct ShowWorker { ct.setup_internals(); ct.setup_internals_mem(); + ct.setup_internals_anyinit(); ct.setup_stdcells(); ct.setup_stdcells_mem(); ct.setup_design(design); diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc index a2d38a0bd..f829714c4 100644 --- a/passes/fsm/fsm_detect.cc +++ b/passes/fsm/fsm_detect.cc @@ -280,6 +280,7 @@ struct FsmDetectPass : public Pass { CellTypes ct; ct.setup_internals(); + ct.setup_internals_anyinit(); ct.setup_internals_mem(); ct.setup_stdcells(); ct.setup_stdcells_mem(); diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc index 845dc850f..c0c40671d 100644 --- a/passes/hierarchy/submod.cc +++ b/passes/hierarchy/submod.cc @@ -260,6 +260,7 @@ struct SubmodWorker } ct.setup_internals(); + ct.setup_internals_anyinit(); ct.setup_internals_mem(); ct.setup_stdcells(); ct.setup_stdcells_mem(); diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index cb2c261c4..dde7c5299 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -633,6 +633,7 @@ struct OptCleanPass : public Pass { keep_cache.reset(design); ct_reg.setup_internals_mem(); + ct_reg.setup_internals_anyinit(); ct_reg.setup_stdcells_mem(); ct_all.setup(design); @@ -694,6 +695,7 @@ struct CleanPass : public Pass { keep_cache.reset(design); ct_reg.setup_internals_mem(); + ct_reg.setup_internals_anyinit(); ct_reg.setup_stdcells_mem(); ct_all.setup(design); diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc index da6d49433..ebe3dc536 100644 --- a/passes/sat/Makefile.inc +++ b/passes/sat/Makefile.inc @@ -10,6 +10,7 @@ OBJS += passes/sat/expose.o OBJS += passes/sat/assertpmux.o OBJS += passes/sat/clk2fflogic.o OBJS += passes/sat/async2sync.o +OBJS += passes/sat/formalff.o OBJS += passes/sat/supercover.o OBJS += passes/sat/fmcombine.o OBJS += passes/sat/mutate.o diff --git a/passes/sat/formalff.cc b/passes/sat/formalff.cc new file mode 100644 index 000000000..fe6f98c16 --- /dev/null +++ b/passes/sat/formalff.cc @@ -0,0 +1,192 @@ +/* + * 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/yosys.h" +#include "kernel/sigtools.h" +#include "kernel/ffinit.h" +#include "kernel/ff.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct FormalFfPass : public Pass { + FormalFfPass() : Pass("formalff", "prepare FFs for formal") { } + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" formalff [options] [selection]\n"); + log("\n"); + log("This pass transforms clocked flip-flops to prepare a design for formal\n"); + log("verification. If a design contains latches and/or multiple different clocks run\n"); + log("the async2sync or clk2fflogic passes before using this pass.\n"); + log("\n"); + log(" -clk2ff\n"); + log(" Replace all clocked flip-flops with $ff cells that use the implicit\n"); + log(" global clock. This assumes, without checking, that the design uses a\n"); + log(" single global clock. If that is not the case, the clk2fflogic pass\n"); + log(" should be used instead.\n"); + log("\n"); + log(" -ff2anyinit\n"); + log(" Replace uninitialized bits of $ff cells with $anyinit cells. An\n"); + log(" $anyinit cell behaves exactly like an $ff cell with an undefined\n"); + log(" initialization value. The difference is that $anyinit inhibits\n"); + log(" don't-care optimizations and is used to track solver-provided values\n"); + log(" in witness traces.\n"); + log("\n"); + log(" If combined with -clk2ff this also affects newly created $ff cells.\n"); + log("\n"); + log(" -anyinit2ff\n"); + log(" Replaces $anyinit cells with uninitialized $ff cells. This performs the\n"); + log(" reverse of -ff2anyinit and can be used, before running a backend pass\n"); + log(" (or similar) that is not yet aware of $anyinit cells.\n"); + log("\n"); + log(" Note that after running -anyinit2ff, in general, performing don't-care\n"); + log(" optimizations is not sound in a formal verification setting.\n"); + log("\n"); + log(" -fine\n"); + log(" Emit fine-grained $_FF_ cells instead of coarse-grained $ff cells for\n"); + log(" -anyinit2ff. Cannot be combined with -clk2ff or -ff2anyinit.\n"); + log("\n"); + + // TODO: An option to check whether all FFs use the same clock before changing it to the global clock + } + void execute(std::vector args, RTLIL::Design *design) override + { + bool flag_clk2ff = false; + bool flag_ff2anyinit = false; + bool flag_anyinit2ff = false; + bool flag_fine = false; + + log_header(design, "Executing FORMALFF pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-clk2ff") { + flag_clk2ff = true; + continue; + } + if (args[argidx] == "-ff2anyinit") { + flag_ff2anyinit = true; + continue; + } + if (args[argidx] == "-anyinit2ff") { + flag_anyinit2ff = true; + continue; + } + if (args[argidx] == "-fine") { + flag_fine = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + if (!(flag_clk2ff || flag_ff2anyinit || flag_anyinit2ff)) + log_cmd_error("One of the options -clk2ff, -ff2anyinit, or -anyinit2ff must be specified.\n"); + + if (flag_ff2anyinit && flag_anyinit2ff) + log_cmd_error("The options -ff2anyinit and -anyinit2ff are exclusive.\n"); + + if (flag_fine && !flag_anyinit2ff) + log_cmd_error("The option -fine requries the -anyinit2ff option.\n"); + + if (flag_fine && flag_clk2ff) + log_cmd_error("The options -fine and -clk2ff are exclusive.\n"); + + for (auto module : design->selected_modules()) + { + SigMap sigmap(module); + FfInitVals initvals(&sigmap, module); + + + for (auto cell : module->selected_cells()) + { + if (flag_anyinit2ff && cell->type == ID($anyinit)) + { + FfData ff(&initvals, cell); + ff.remove(); + ff.is_anyinit = false; + ff.is_fine = flag_fine; + if (flag_fine) + for (int i = 0; i < ff.width; i++) + ff.slice({i}).emit(); + else + ff.emit(); + + continue; + } + + if (!RTLIL::builtin_ff_cell_types().count(cell->type)) + continue; + + FfData ff(&initvals, cell); + bool emit = false; + + if (flag_clk2ff && ff.has_clk) { + if (ff.sig_clk.is_fully_const()) + log_error("Const CLK on %s (%s) from module %s, run async2sync first.\n", + log_id(cell), log_id(cell->type), log_id(module)); + + ff.unmap_ce_srst(); + ff.has_clk = false; + ff.has_gclk = true; + emit = true; + } + + if (!ff.has_gclk) { + continue; + } + + if (flag_ff2anyinit && !ff.val_init.is_fully_def()) + { + ff.remove(); + emit = false; + + int cursor = 0; + while (cursor < ff.val_init.size()) + { + bool is_anyinit = ff.val_init[cursor] == State::Sx; + std::vector bits; + bits.push_back(cursor++); + while (cursor < ff.val_init.size() && (ff.val_init[cursor] == State::Sx) == is_anyinit) + bits.push_back(cursor++); + + if ((int)bits.size() == ff.val_init.size()) { + // This check is only to make the private names more helpful for debugging + ff.is_anyinit = true; + emit = true; + break; + } + + auto slice = ff.slice(bits); + slice.is_anyinit = is_anyinit; + slice.emit(); + } + } + + if (emit) + ff.emit(); + } + } + } +} FormalFfPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 53644c6b7..ea64dce06 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -231,7 +231,7 @@ struct SimInstance } } - if (RTLIL::builtin_ff_cell_types().count(cell->type)) { + if (RTLIL::builtin_ff_cell_types().count(cell->type) || cell->type == ID($anyinit)) { FfData ff_data(nullptr, cell); ff_state_t ff; ff.past_d = Const(State::Sx, ff_data.width); diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index b14488ff4..ab9bd7e1d 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -1696,6 +1696,23 @@ assign Y = 'bx; endmodule +// -------------------------------------------------------- +`ifdef SIMLIB_FF +module \$anyinit (D, Q); + +parameter WIDTH = 0; + +input [WIDTH-1:0] D; +output reg [WIDTH-1:0] Q; + +initial Q <= 'bx; + +always @($global_clk) begin + Q <= D; +end + +endmodule +`endif // -------------------------------------------------------- module \$allconst (Y); -- cgit v1.2.3 From a5e1d3b9974668b4ab526a6b77ca96f1aa16d01f Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 2 Aug 2022 15:49:51 +0200 Subject: formalff: Set new replaced_by_gclk attribute on removed dff's clks This attribute can be used by formal backends to indicate which clocks were mapped to the global clock. Update the btor and smt2 backend which already handle clock inputs to understand this attribute. --- backends/btor/btor.cc | 10 ++++++++++ backends/smt2/smt2.cc | 11 +++++++++++ kernel/constids.inc | 1 + passes/sat/formalff.cc | 22 ++++++++++++++++++++++ 4 files changed, 44 insertions(+) diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index 831a3ada2..6dae7156a 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -1112,6 +1112,16 @@ struct BtorWorker btorf("%d input %d%s\n", nid, sid, getinfo(wire).c_str()); add_nid_sig(nid, sig); + + if (!info_filename.empty()) { + auto gclk_attr = wire->attributes.find(ID::replaced_by_gclk); + if (gclk_attr != wire->attributes.end()) { + if (gclk_attr->second == State::S1) + info_clocks[nid] |= 1; + else if (gclk_attr->second == State::S0) + info_clocks[nid] |= 2; + } + } } btorf_pop("inputs"); diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index f6c3560c1..126ee1175 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -239,6 +239,17 @@ struct Smt2Worker clock_negedge.erase(bit); } + for (auto wire : module->wires()) + { + auto gclk_attr = wire->attributes.find(ID::replaced_by_gclk); + if (gclk_attr != wire->attributes.end()) { + if (gclk_attr->second == State::S1) + clock_posedge.insert(sigmap(wire)); + else if (gclk_attr->second == State::S0) + clock_negedge.insert(sigmap(wire)); + } + } + for (auto wire : module->wires()) { if (!wire->port_input || GetSize(wire) != 1) diff --git a/kernel/constids.inc b/kernel/constids.inc index 0f6dfc29b..239381f85 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -171,6 +171,7 @@ X(RD_TRANSPARENCY_MASK) X(RD_TRANSPARENT) X(RD_WIDE_CONTINUATION) X(reg) +X(replaced_by_gclk) X(reprocess_after) X(rom_block) X(rom_style) diff --git a/passes/sat/formalff.cc b/passes/sat/formalff.cc index fe6f98c16..0c85c3442 100644 --- a/passes/sat/formalff.cc +++ b/passes/sat/formalff.cc @@ -145,6 +145,28 @@ struct FormalFfPass : public Pass { log_error("Const CLK on %s (%s) from module %s, run async2sync first.\n", log_id(cell), log_id(cell->type), log_id(module)); + auto clk_wire = ff.sig_clk.is_wire() ? ff.sig_clk.as_wire() : nullptr; + + if (clk_wire == nullptr) { + clk_wire = module->addWire(NEW_ID); + module->connect(RTLIL::SigBit(clk_wire), ff.sig_clk); + } + + auto clk_polarity = ff.pol_clk ? State::S1 : State::S0; + + std::string attribute = clk_wire->get_string_attribute(ID::replaced_by_gclk); + + auto &attr = clk_wire->attributes[ID::replaced_by_gclk]; + + if (!attr.empty() && attr != clk_polarity) + log_error("CLK %s on %s (%s) from module %s also used with opposite polarity, run clk2fflogic instead.\n", + log_id(clk_wire), log_id(cell), log_id(cell->type), log_id(module)); + + attr = clk_polarity; + clk_wire->set_bool_attribute(ID::keep); + + // TODO propagate the replaced_by_gclk attribute upwards throughout the hierarchy + ff.unmap_ce_srst(); ff.has_clk = false; ff.has_gclk = true; -- cgit v1.2.3 From 95db5a9d3899973c0c7bcfa887f8404ac017d53f Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Fri, 5 Aug 2022 15:43:08 +0200 Subject: formalff: New -setundef option Find FFs with undefined initialization values for which changing the initialization does not change the observable behavior and initialize them. For -ff2anyinit, this reduces the number of generated $anyinit cells that drive wires with private names. --- passes/sat/formalff.cc | 335 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 335 insertions(+) diff --git a/passes/sat/formalff.cc b/passes/sat/formalff.cc index 0c85c3442..209486a37 100644 --- a/passes/sat/formalff.cc +++ b/passes/sat/formalff.cc @@ -21,10 +21,302 @@ #include "kernel/sigtools.h" #include "kernel/ffinit.h" #include "kernel/ff.h" +#include "kernel/modtools.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN + +// Finds signal values with known constant or known unused values in the initial state +struct InitValWorker +{ + Module *module; + + ModWalker modwalker; + SigMap &sigmap; + FfInitVals initvals; + + dict initconst_bits; + dict used_bits; + + InitValWorker(Module *module) : module(module), modwalker(module->design), sigmap(modwalker.sigmap) + { + modwalker.setup(module); + initvals.set(&modwalker.sigmap, module); + + for (auto wire : module->wires()) + if (wire->name.isPublic() || wire->get_bool_attribute(ID::keep)) + for (auto bit : SigSpec(wire)) + used_bits[sigmap(bit)] = true; + } + + // Sign/Zero-extended indexing of individual port bits + static SigBit bit_in_port(RTLIL::Cell *cell, RTLIL::IdString port, RTLIL::IdString sign, int index) + { + auto sig_port = cell->getPort(port); + if (index < GetSize(sig_port)) + return sig_port[index]; + else if (cell->getParam(sign).as_bool()) + return GetSize(sig_port) > 0 ? sig_port[GetSize(sig_port) - 1] : State::Sx; + else + return State::S0; + } + + // Has the signal a known constant value in the initial state? + // + // For sync-only FFs outputs, this is their initval. For logic loops, + // multiple drivers or unknown cells this is Sx. For a small number of + // handled cells we recurse through their inputs. All results are cached. + RTLIL::State initconst(SigBit bit) + { + sigmap.apply(bit); + + if (!bit.is_wire()) + return bit.data; + + auto it = initconst_bits.find(bit); + if (it != initconst_bits.end()) + return it->second; + + // Setting this temporarily to x takes care of any logic loops + initconst_bits[bit] = State::Sx; + + pool portbits; + modwalker.get_drivers(portbits, {bit}); + + if (portbits.size() != 1) + return State::Sx; + + ModWalker::PortBit portbit = *portbits.begin(); + RTLIL::Cell *cell = portbit.cell; + + if (RTLIL::builtin_ff_cell_types().count(cell->type)) + { + FfData ff(&initvals, cell); + + if (ff.has_aload || ff.has_sr || ff.has_arst || (!ff.has_clk && !ff.has_gclk)) { + for (auto bit_q : ff.sig_q) { + initconst_bits[sigmap(bit_q)] = State::Sx; + } + return State::Sx; + } + + for (int i = 0; i < ff.width; i++) { + initconst_bits[sigmap(ff.sig_q[i])] = ff.val_init[i]; + } + + return ff.val_init[portbit.offset]; + } + + if (cell->type.in(ID($mux), ID($and), ID($or), ID($eq), ID($eqx), ID($initstate))) + { + if (cell->type == ID($mux)) + { + SigBit sig_s = sigmap(cell->getPort(ID::S)); + State init_s = initconst(sig_s); + State init_y; + + if (init_s == State::S0) { + init_y = initconst(cell->getPort(ID::A)[portbit.offset]); + } else if (init_s == State::S1) { + init_y = initconst(cell->getPort(ID::B)[portbit.offset]); + } else { + State init_a = initconst(cell->getPort(ID::A)[portbit.offset]); + State init_b = initconst(cell->getPort(ID::B)[portbit.offset]); + init_y = init_a == init_b ? init_a : State::Sx; + } + initconst_bits[bit] = init_y; + return init_y; + } + + if (cell->type.in(ID($and), ID($or))) + { + State init_a = initconst(bit_in_port(cell, ID::A, ID::A_SIGNED, portbit.offset)); + State init_b = initconst(bit_in_port(cell, ID::B, ID::B_SIGNED, portbit.offset)); + State init_y; + if (init_a == init_b) + init_y = init_a; + else if (cell->type == ID($and) && (init_a == State::S0 || init_b == State::S0)) + init_y = State::S0; + else if (cell->type == ID($or) && (init_a == State::S1 || init_b == State::S1)) + init_y = State::S1; + else + init_y = State::Sx; + + initconst_bits[bit] = init_y; + return init_y; + } + + if (cell->type.in(ID($eq), ID($eqx))) // Treats $eqx as $eq + { + if (portbit.offset > 0) { + initconst_bits[bit] = State::S0; + return State::S0; + } + + SigSpec sig_a = cell->getPort(ID::A); + SigSpec sig_b = cell->getPort(ID::B); + + State init_y = State::S1; + + for (int i = 0; init_y != State::S0 && i < GetSize(sig_a); i++) { + State init_ai = initconst(bit_in_port(cell, ID::A, ID::A_SIGNED, i)); + if (init_ai == State::Sx) { + init_y = State::Sx; + continue; + } + State init_bi = initconst(bit_in_port(cell, ID::B, ID::B_SIGNED, i)); + if (init_bi == State::Sx) + init_y = State::Sx; + else if (init_ai != init_bi) + init_y = State::S0; + } + + initconst_bits[bit] = init_y; + return init_y; + } + + if (cell->type == ID($initstate)) + { + initconst_bits[bit] = State::S1; + return State::S1; + } + + log_assert(false); + } + + return State::Sx; + } + + RTLIL::Const initconst(SigSpec sig) + { + std::vector bits; + for (auto bit : sig) + bits.push_back(initconst(bit)); + return bits; + } + + // Is the initial value of this signal used? + // + // An initial value of a signal is considered as used if it a) aliases a + // wire with a public name, an output wire or with a keep attribute b) + // combinationally drives such a wire or c) drive an input to an unknown + // cell. + // + // This recurses into driven cells for a small number of known handled + // celltypes. Results are cached and initconst is used to detect unused + // inputs for the handled celltypes. + bool is_initval_used(SigBit bit) + { + if (!bit.is_wire()) + return false; + + auto it = used_bits.find(bit); + if (it != used_bits.end()) + return it->second; + + used_bits[bit] = true; // Temporarily set to guard against logic loops + + pool portbits; + modwalker.get_consumers(portbits, {bit}); + + for (auto portbit : portbits) { + RTLIL::Cell *cell = portbit.cell; + if (!cell->type.in(ID($mux), ID($and), ID($or), ID($mem_v2)) && !RTLIL::builtin_ff_cell_types().count(cell->type)) { + return true; + } + } + + for (auto portbit : portbits) + { + RTLIL::Cell *cell = portbit.cell; + if (RTLIL::builtin_ff_cell_types().count(cell->type)) + { + FfData ff(&initvals, cell); + if (ff.has_aload || ff.has_sr || ff.has_arst || ff.has_gclk || !ff.has_clk) + return true; + if (ff.has_ce && initconst(ff.sig_ce.as_bit()) == (ff.pol_ce ? State::S0 : State::S1)) + continue; + if (ff.has_srst && initconst(ff.sig_ce.as_bit()) == (ff.pol_srst ? State::S1 : State::S0)) + continue; + + return true; + } + else if (cell->type == ID($mux)) + { + State init_s = initconst(cell->getPort(ID::S).as_bit()); + if (init_s == State::S0 && portbit.port == ID::B) + continue; + if (init_s == State::S1 && portbit.port == ID::A) + continue; + auto sig_y = cell->getPort(ID::Y); + + if (is_initval_used(sig_y[portbit.offset])) + return true; + } + else if (cell->type.in(ID($and), ID($or))) + { + auto sig_a = cell->getPort(ID::A); + auto sig_b = cell->getPort(ID::B); + auto sig_y = cell->getPort(ID::Y); + if (GetSize(sig_y) != GetSize(sig_a) || GetSize(sig_y) != GetSize(sig_b)) + return true; // TODO handle more of this + State absorbing = cell->type == ID($and) ? State::S0 : State::S1; + if (portbit.port == ID::A && initconst(sig_b[portbit.offset]) == absorbing) + continue; + if (portbit.port == ID::B && initconst(sig_a[portbit.offset]) == absorbing) + continue; + + if (is_initval_used(sig_y[portbit.offset])) + return true; + } + else if (cell->type == ID($mem_v2)) + { + // TODO Use mem.h instead to uniformily cover all cases, most + // likely requires processing all memories when initializing + // the worker + if (!portbit.port.in(ID::WR_DATA, ID::WR_ADDR, ID::RD_ADDR)) + return true; + + if (portbit.port == ID::WR_DATA) + { + if (initconst(cell->getPort(ID::WR_EN)[portbit.offset]) == State::S0) + continue; + } + else if (portbit.port == ID::WR_ADDR) + { + int port = portbit.offset / cell->getParam(ID::ABITS).as_int(); + auto sig_en = cell->getPort(ID::WR_EN); + int width = cell->getParam(ID::WIDTH).as_int(); + + for (int i = port * width; i < (port + 1) * width; i++) + if (initconst(sig_en[i]) != State::S0) + return true; + + continue; + } + else if (portbit.port == ID::RD_ADDR) + { + int port = portbit.offset / cell->getParam(ID::ABITS).as_int(); + auto sig_en = cell->getPort(ID::RD_EN); + + if (initconst(sig_en[port]) != State::S0) + return true; + + continue; + } + else + return true; + } + else + log_assert(false); + } + + used_bits[bit] = false; + return false; + } +}; + struct FormalFfPass : public Pass { FormalFfPass() : Pass("formalff", "prepare FFs for formal") { } void help() override @@ -64,6 +356,12 @@ struct FormalFfPass : public Pass { log(" Emit fine-grained $_FF_ cells instead of coarse-grained $ff cells for\n"); log(" -anyinit2ff. Cannot be combined with -clk2ff or -ff2anyinit.\n"); log("\n"); + log(" -setundef\n"); + log(" Find FFs with undefined initialization values for which changing the\n"); + log(" initialization does not change the observable behavior and initialize\n"); + log(" them. For -ff2anyinit, this reduces the number of generated $anyinit\n"); + log(" cells that drive wires with private names.\n"); + log("\n"); // TODO: An option to check whether all FFs use the same clock before changing it to the global clock } @@ -73,6 +371,7 @@ struct FormalFfPass : public Pass { bool flag_ff2anyinit = false; bool flag_anyinit2ff = false; bool flag_fine = false; + bool flag_setundef = false; log_header(design, "Executing FORMALFF pass.\n"); @@ -95,6 +394,10 @@ struct FormalFfPass : public Pass { flag_fine = true; continue; } + if (args[argidx] == "-setundef") { + flag_setundef = true; + continue; + } break; } extra_args(args, argidx, design); @@ -113,6 +416,38 @@ struct FormalFfPass : public Pass { for (auto module : design->selected_modules()) { + if (flag_setundef) + { + InitValWorker worker(module); + + for (auto cell : module->selected_cells()) + { + if (RTLIL::builtin_ff_cell_types().count(cell->type)) + { + FfData ff(&worker.initvals, cell); + if (ff.has_aload || ff.has_sr || ff.has_arst || ff.val_init.is_fully_def()) + continue; + + if (ff.has_ce && // CE can make the initval stick around + worker.initconst(ff.sig_ce.as_bit()) != (ff.pol_ce ? State::S1 : State::S0) && // unless it's known active + (!ff.has_srst || ff.ce_over_srst || + worker.initconst(ff.sig_srst.as_bit()) != (ff.pol_srst ? State::S1 : State::S0))) // or a srst with priority is known active + continue; + + auto before = ff.val_init; + for (int i = 0; i < ff.width; i++) + if (ff.val_init[i] == State::Sx && !worker.is_initval_used(ff.sig_q[i])) + ff.val_init[i] = State::S0; + + if (ff.val_init != before) { + log("Setting unused undefined initial value of %s.%s (%s) from %s to %s\n", + log_id(module), log_id(cell), log_id(cell->type), + log_const(before), log_const(ff.val_init)); + worker.initvals.set_init(ff.sig_q, ff.val_init); + } + } + } + } SigMap sigmap(module); FfInitVals initvals(&sigmap, module); -- cgit v1.2.3 From 428ad5b9fd1861d7943c29e7927969a02b14926b Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Wed, 20 Jul 2022 11:31:06 +0200 Subject: wreduce: Keep more x-bits with -keepdc --- passes/opt/wreduce.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 08ab6de6f..8fd4c788c 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -166,8 +166,8 @@ struct WreduceWorker for (int i = GetSize(sig_q)-1; i >= 0; i--) { - if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx) && - (!has_reset || i >= GetSize(rst_value) || rst_value[i] == State::S0 || rst_value[i] == State::Sx)) { + if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || (!config->keepdc && initval[i] == State::Sx)) && + (!has_reset || i >= GetSize(rst_value) || rst_value[i] == State::S0 || (!config->keepdc && rst_value[i] == State::Sx))) { module->connect(sig_q[i], State::S0); initvals.remove_init(sig_q[i]); sig_d.remove(i); @@ -175,8 +175,8 @@ struct WreduceWorker continue; } - if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1] && - (!has_reset || i >= GetSize(rst_value) || rst_value[i] == rst_value[i-1])) { + if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1] && (!config->keepdc || initval[i] != State::Sx) && + (!has_reset || i >= GetSize(rst_value) || (rst_value[i] == rst_value[i-1] && (!config->keepdc || rst_value[i] != State::Sx)))) { module->connect(sig_q[i], sig_q[i-1]); initvals.remove_init(sig_q[i]); sig_d.remove(i); -- cgit v1.2.3 From 0cdb14df41be53f770390d6ad01cf650f1bc49da Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 2 Aug 2022 15:36:29 +0200 Subject: setundef: Do not add anyseq / anyconst to unused memory port clocks Instead set those unused clocks to zero. --- passes/cmds/setundef.cc | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc index a078b0b1c..590a7eb1d 100644 --- a/passes/cmds/setundef.cc +++ b/passes/cmds/setundef.cc @@ -20,6 +20,7 @@ #include "kernel/register.h" #include "kernel/celltypes.h" #include "kernel/sigtools.h" +#include "kernel/mem.h" #include "kernel/rtlil.h" #include "kernel/log.h" @@ -478,6 +479,29 @@ struct SetundefPass : public Pass { log_assert(ffbits.empty()); } + if (worker.next_bit_mode == MODE_ANYSEQ || worker.next_bit_mode == MODE_ANYCONST) + { + // Do not add anyseq / anyconst to unused memory port clocks + std::vector memories = Mem::get_selected_memories(module); + for (auto &mem : memories) { + bool changed = false; + for (auto &rd_port : mem.rd_ports) { + if (!rd_port.clk_enable && rd_port.clk.is_fully_undef()) { + changed = true; + rd_port.clk = State::S0; + } + } + for (auto &wr_port : mem.rd_ports) { + if (!wr_port.clk_enable && wr_port.clk.is_fully_undef()) { + changed = true; + wr_port.clk = State::S0; + } + } + if (changed) + mem.emit(); + } + } + module->rewrite_sigspecs(worker); if (worker.next_bit_mode == MODE_ANYSEQ || worker.next_bit_mode == MODE_ANYCONST) -- cgit v1.2.3 From a2f9ebe43a287233917947851e0d0dff803a4675 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 2 Aug 2022 16:07:28 +0200 Subject: memory_map: Add -formal option This maps memories for a global clock based formal verification flow. This implies -keepdc, uses $ff cells for ROMs and sets hdlname attributes. --- CHANGELOG | 1 + passes/memory/memory_map.cc | 84 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 68 insertions(+), 17 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 199d6a61a..5ee3e3cc0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,7 @@ Yosys 0.20 .. Yosys 0.20-dev -------------------------- * New commands and options - Added "formalff" pass - transforms FFs for formal verification + - Added option "-formal" to "memory_map" pass * Formal Verification - Added $anyinit cell to directly represent FFs with an unconstrained diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index fd5b1f1ad..e2f74c2e1 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -32,6 +32,7 @@ struct MemoryMapWorker bool attr_icase = false; bool rom_only = false; bool keepdc = false; + bool formal = false; dict> attributes; RTLIL::Design *design; @@ -151,6 +152,8 @@ struct MemoryMapWorker // all write ports must share the same clock RTLIL::SigSpec refclock; bool refclock_pol = false; + bool async_wr = false; + bool static_only = true; for (int i = 0; i < GetSize(mem.wr_ports); i++) { auto &port = mem.wr_ports[i]; if (port.en.is_fully_const() && !port.en.as_bool()) { @@ -164,10 +167,20 @@ struct MemoryMapWorker static_ports.insert(i); continue; } - log("Not mapping memory %s in module %s (write port %d has no clock).\n", - mem.memid.c_str(), module->name.c_str(), i); - return; + static_only = false; + if (GetSize(refclock) != 0) + log("Not mapping memory %s in module %s (mixed clocked and async write ports).\n", + mem.memid.c_str(), module->name.c_str()); + if (!formal) + log("Not mapping memory %s in module %s (write port %d has no clock).\n", + mem.memid.c_str(), module->name.c_str(), i); + async_wr = true; + continue; } + static_only = false; + if (async_wr) + log("Not mapping memory %s in module %s (mixed clocked and async write ports).\n", + mem.memid.c_str(), module->name.c_str()); if (refclock.size() == 0) { refclock = port.clk; refclock_pol = port.clk_polarity; @@ -185,6 +198,8 @@ struct MemoryMapWorker std::vector data_reg_in(1 << abits); std::vector data_reg_out(1 << abits); + std::vector &data_read = async_wr ? data_reg_in : data_reg_out; + int count_static = 0; for (int i = 0; i < mem.size; i++) @@ -194,24 +209,36 @@ struct MemoryMapWorker SigSpec w_init = init_data.extract(i*mem.width, mem.width); if (static_cells_map.count(addr) > 0) { - data_reg_out[idx] = static_cells_map[addr]; + data_read[idx] = static_cells_map[addr]; count_static++; } - else if (mem.wr_ports.empty() && (!keepdc || w_init.is_fully_def())) + else if (static_only && (!keepdc || w_init.is_fully_def())) { - data_reg_out[idx] = w_init; + data_read[idx] = w_init; } else { - RTLIL::Cell *c = module->addCell(genid(mem.memid, "", addr), ID($dff)); - c->parameters[ID::WIDTH] = mem.width; - if (GetSize(refclock) != 0) { + RTLIL::Cell *c; + auto ff_id = genid(mem.memid, "", addr); + + if (static_only) { + // non-static part is a ROM, we only reach this with keepdc + if (formal) { + c = module->addCell(ff_id, ID($ff)); + } else { + c = module->addCell(ff_id, ID($dff)); + c->parameters[ID::CLK_POLARITY] = RTLIL::Const(RTLIL::State::S1); + c->setPort(ID::CLK, RTLIL::SigSpec(RTLIL::State::S0)); + } + } else if (async_wr) { + log_assert(formal); // General async write not implemented yet, checked against above + c = module->addCell(ff_id, ID($ff)); + } else { + c = module->addCell(ff_id, ID($dff)); c->parameters[ID::CLK_POLARITY] = RTLIL::Const(refclock_pol); c->setPort(ID::CLK, refclock); - } else { - c->parameters[ID::CLK_POLARITY] = RTLIL::Const(RTLIL::State::S1); - c->setPort(ID::CLK, RTLIL::SigSpec(RTLIL::State::S0)); } + c->parameters[ID::WIDTH] = mem.width; RTLIL::Wire *w_in = module->addWire(genid(mem.memid, "", addr, "$d"), mem.width); data_reg_in[idx] = w_in; @@ -223,18 +250,27 @@ struct MemoryMapWorker RTLIL::Wire *w_out = module->addWire(w_out_name, mem.width); + if (formal && mem.packed && mem.cell->name.c_str()[0] == '\\') { + auto hdlname = mem.cell->get_hdlname_attribute(); + if (hdlname.empty()) + hdlname.push_back(mem.cell->name.c_str() + 1); + hdlname.push_back(stringf("[%d]", addr)); + w_out->set_hdlname_attribute(hdlname); + } + if (!w_init.is_fully_undef()) w_out->attributes[ID::init] = w_init.as_const(); data_reg_out[idx] = w_out; c->setPort(ID::Q, w_out); - if (mem.wr_ports.empty()) + if (static_only) module->connect(RTLIL::SigSig(w_in, w_out)); } } - log(" created %d $dff cells and %d static cells of width %d.\n", mem.size-count_static, count_static, mem.width); + log(" created %d %s cells and %d static cells of width %d.\n", + mem.size-count_static, formal && (static_only || async_wr) ? "$ff" : "$dff", count_static, mem.width); int count_dff = 0, count_mux = 0, count_wrmux = 0; @@ -272,13 +308,13 @@ struct MemoryMapWorker } for (int j = 0; j < (1 << abits); j++) - if (data_reg_out[j] != SigSpec()) - module->connect(RTLIL::SigSig(rd_signals[j >> port.wide_log2].extract((j & ((1 << port.wide_log2) - 1)) * mem.width, mem.width), data_reg_out[j])); + if (data_read[j] != SigSpec()) + module->connect(RTLIL::SigSig(rd_signals[j >> port.wide_log2].extract((j & ((1 << port.wide_log2) - 1)) * mem.width, mem.width), data_read[j])); } log(" read interface: %d $dff and %d $mux cells.\n", count_dff, count_mux); - if (!mem.wr_ports.empty()) + if (!static_only) { for (int i = 0; i < mem.size; i++) { @@ -387,12 +423,19 @@ struct MemoryMapPass : public Pass { log(" -keepdc\n"); log(" when mapping ROMs, keep x-bits shared across read ports.\n"); log("\n"); + log(" -formal\n"); + log(" map memories for a global clock based formal verification flow.\n"); + log(" This implies -keepdc, uses $ff cells for ROMs and sets hdlname\n"); + log(" attributes. It also has limited support for async write ports\n"); + log(" as generated by clk2fflogic.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { bool attr_icase = false; bool rom_only = false; bool keepdc = false; + bool formal = false; dict> attributes; log_header(design, "Executing MEMORY_MAP pass (converting memories to logic and flip-flops).\n"); @@ -439,6 +482,12 @@ struct MemoryMapPass : public Pass { keepdc = true; continue; } + if (args[argidx] == "-formal") + { + formal = true; + keepdc = true; + continue; + } break; } extra_args(args, argidx, design); @@ -449,6 +498,7 @@ struct MemoryMapPass : public Pass { worker.attributes = attributes; worker.rom_only = rom_only; worker.keepdc = keepdc; + worker.formal = formal; worker.run(); } } -- cgit v1.2.3 From 021c3c8da52ebaf6088ea740fdc12b496bfc338a Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 2 Aug 2022 15:53:47 +0200 Subject: smt2: Support $anyinit cells --- backends/smt2/smt2.cc | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index 126ee1175..e6729aade 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -594,25 +594,26 @@ struct Smt2Worker return; } - if (cell->type.in(ID($anyconst), ID($anyseq), ID($allconst), ID($allseq))) + if (cell->type.in(ID($anyconst), ID($anyseq), ID($anyinit), ID($allconst), ID($allseq))) { + auto QY = cell->type == ID($anyinit) ? ID::Q : ID::Y; registers.insert(cell); string infostr = cell->attributes.count(ID::src) ? cell->attributes.at(ID::src).decode_string().c_str() : get_id(cell); if (cell->attributes.count(ID::reg)) infostr += " " + cell->attributes.at(ID::reg).decode_string(); - decls.push_back(stringf("; yosys-smt2-%s %s#%d %d %s\n", cell->type.c_str() + 1, get_id(module), idcounter, GetSize(cell->getPort(ID::Y)), infostr.c_str())); - if (cell->getPort(ID::Y).is_wire() && cell->getPort(ID::Y).as_wire()->get_bool_attribute(ID::maximize)){ + decls.push_back(stringf("; yosys-smt2-%s %s#%d %d %s\n", cell->type.c_str() + 1, get_id(module), idcounter, GetSize(cell->getPort(QY)), infostr.c_str())); + if (cell->getPort(QY).is_wire() && cell->getPort(QY).as_wire()->get_bool_attribute(ID::maximize)){ decls.push_back(stringf("; yosys-smt2-maximize %s#%d\n", get_id(module), idcounter)); - log("Wire %s is maximized\n", cell->getPort(ID::Y).as_wire()->name.str().c_str()); + log("Wire %s is maximized\n", cell->getPort(QY).as_wire()->name.str().c_str()); } - else if (cell->getPort(ID::Y).is_wire() && cell->getPort(ID::Y).as_wire()->get_bool_attribute(ID::minimize)){ + else if (cell->getPort(QY).is_wire() && cell->getPort(QY).as_wire()->get_bool_attribute(ID::minimize)){ decls.push_back(stringf("; yosys-smt2-minimize %s#%d\n", get_id(module), idcounter)); - log("Wire %s is minimized\n", cell->getPort(ID::Y).as_wire()->name.str().c_str()); + log("Wire %s is minimized\n", cell->getPort(QY).as_wire()->name.str().c_str()); } - makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(cell->getPort(ID::Y)), log_signal(cell->getPort(ID::Y))); + makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(cell->getPort(QY)), log_signal(cell->getPort(QY))); if (cell->type == ID($anyseq)) ex_input_eq.push_back(stringf(" (= (|%s#%d| state) (|%s#%d| other_state))", get_id(module), idcounter, get_id(module), idcounter)); - register_bv(cell->getPort(ID::Y), idcounter++); + register_bv(cell->getPort(QY), idcounter++); recursive_cells.erase(cell); return; } @@ -931,7 +932,7 @@ struct Smt2Worker pool reg_bits; for (auto cell : module->cells()) - if (cell->type.in(ID($ff), ID($dff), ID($_FF_), ID($_DFF_P_), ID($_DFF_N_))) { + if (cell->type.in(ID($ff), ID($dff), ID($_FF_), ID($_DFF_P_), ID($_DFF_N_), ID($anyinit))) { // not using sigmap -- we want the net directly at the dff output for (auto bit : cell->getPort(ID::Q)) reg_bits.insert(bit); @@ -1147,7 +1148,7 @@ struct Smt2Worker ex_state_eq.push_back(stringf("(= %s %s)", get_bool(cell->getPort(ID::Q)).c_str(), get_bool(cell->getPort(ID::Q), "other_state").c_str())); } - if (cell->type.in(ID($ff), ID($dff))) + if (cell->type.in(ID($ff), ID($dff), ID($anyinit))) { std::string expr_d = get_bv(cell->getPort(ID::D)); std::string expr_q = get_bv(cell->getPort(ID::Q), "next_state"); -- cgit v1.2.3 From 5893cae6472727a71573cb0826158125a6aa04af Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 2 Aug 2022 15:55:54 +0200 Subject: aiger: Support $anyinit cells --- backends/aiger/aiger.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/backends/aiger/aiger.cc b/backends/aiger/aiger.cc index 547d131ee..800743b22 100644 --- a/backends/aiger/aiger.cc +++ b/backends/aiger/aiger.cc @@ -189,6 +189,17 @@ struct AigerWriter continue; } + if (cell->type == ID($anyinit)) + { + auto sig_d = sigmap(cell->getPort(ID::D)); + auto sig_q = sigmap(cell->getPort(ID::Q)); + for (int i = 0; i < sig_d.size(); i++) { + undriven_bits.erase(sig_q[i]); + ff_map[sig_q[i]] = sig_d[i]; + } + continue; + } + if (cell->type == ID($_AND_)) { SigBit A = sigmap(cell->getPort(ID::A).as_bit()); -- cgit v1.2.3 From 96a1173598ec1bf93670b2de3c8bb087f03a8528 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 2 Aug 2022 15:59:39 +0200 Subject: btor: Support $anyinit cells --- backends/btor/btor.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index 6dae7156a..06de71018 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -612,7 +612,7 @@ struct BtorWorker goto okay; } - if (cell->type.in(ID($dff), ID($ff), ID($_DFF_P_), ID($_DFF_N), ID($_FF_))) + if (cell->type.in(ID($dff), ID($ff), ID($anyinit), ID($_DFF_P_), ID($_DFF_N), ID($_FF_))) { SigSpec sig_d = sigmap(cell->getPort(ID::D)); SigSpec sig_q = sigmap(cell->getPort(ID::Q)); -- cgit v1.2.3 From f041e36c6e142878c5bca4da5b459177c4f75e07 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 2 Aug 2022 16:49:36 +0200 Subject: smtbmc: Add native json based witness format + smt2 backend support This adds a native json based witness trace format. By having a common format that includes everything we support, and providing a conversion utility (yosys-witness) we no longer need to implement every format for every tool that deals with witness traces, avoiding a quadratic opportunity to introduce subtle bugs. Included: * smt2: New yosys-smt2-witness info lines containing full hierarchical paths without lossy escaping. * yosys-smtbmc --dump-yw trace.yw: Dump results in the new format. * yosys-smtbmc --yw trace.yw: Read new format as constraints. * yosys-witness: New tool to convert witness formats. Currently this can only display traces in a human-readable-only format and do a passthrough read/write of the new format. * ywio.py: Small python lib for reading and writing the new format. Used by yosys-smtbmc and yosys-witness to avoid duplication. --- .gitignore | 3 + CHANGELOG | 4 + backends/smt2/Makefile.inc | 16 +- backends/smt2/smt2.cc | 120 ++++++++- backends/smt2/smtbmc.py | 400 +++++++++++++++++++++-------- backends/smt2/smtio.py | 63 ++++- backends/smt2/witness.py | 90 +++++++ backends/smt2/ywio.py | 392 ++++++++++++++++++++++++++++ tests/various/smtlib2_module-expected.smt2 | 8 + 9 files changed, 983 insertions(+), 113 deletions(-) create mode 100644 backends/smt2/witness.py create mode 100644 backends/smt2/ywio.py diff --git a/.gitignore b/.gitignore index 0460c7c13..49b886e7e 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,9 @@ __pycache__ /yosys-smtbmc /yosys-smtbmc.exe /yosys-smtbmc-script.py +/yosys-witness +/yosys-witness.exe +/yosys-witness-script.py /yosys-filterlib /yosys-filterlib.exe /kernel/*.pyh diff --git a/CHANGELOG b/CHANGELOG index 5ee3e3cc0..cf2a46bd3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,10 @@ Yosys 0.20 .. Yosys 0.20-dev * Formal Verification - Added $anyinit cell to directly represent FFs with an unconstrained initialization value. These can be generated by the new formalff pass. + - New JSON based yosys witness format for formal verification traces. + - yosys-smtbmc: Reading and writing of yosys witness traces. + - write_smt2: Emit inline metadata to support yosys witness trace. + - yosys-witness is a new tool to inspect and convert yosys witness traces. Yosys 0.19 .. Yosys 0.20 -------------------------- diff --git a/backends/smt2/Makefile.inc b/backends/smt2/Makefile.inc index fb01308bd..3afe990e7 100644 --- a/backends/smt2/Makefile.inc +++ b/backends/smt2/Makefile.inc @@ -7,6 +7,7 @@ ifneq ($(CONFIG),emcc) # MSYS targets support yosys-smtbmc, but require a launcher script ifeq ($(CONFIG),$(filter $(CONFIG),msys2 msys2-64)) TARGETS += $(PROGRAM_PREFIX)yosys-smtbmc.exe $(PROGRAM_PREFIX)yosys-smtbmc-script.py +TARGETS += $(PROGRAM_PREFIX)yosys-witness.exe $(PROGRAM_PREFIX)yosys-witness-script.py # Needed to find the Python interpreter for yosys-smtbmc scripts. # Override if necessary, it is only used for msys2 targets. PYTHON := $(shell cygpath -w -m $(PREFIX)/bin/python3) @@ -15,18 +16,31 @@ $(PROGRAM_PREFIX)yosys-smtbmc-script.py: backends/smt2/smtbmc.py $(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/$(PROGRAM_PREFIX)yosys/python3"]]|;' \ -e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@ +$(PROGRAM_PREFIX)yosys-witness-script.py: backends/smt2/witness.py + $(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/$(PROGRAM_PREFIX)yosys/python3"]]|;' \ + -e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@ + $(PROGRAM_PREFIX)yosys-smtbmc.exe: misc/launcher.c $(PROGRAM_PREFIX)yosys-smtbmc-script.py $(P) $(CXX) -DGUI=0 -O -s -o $@ $< + +$(PROGRAM_PREFIX)yosys-witness.exe: misc/launcher.c $(PROGRAM_PREFIX)yosys-witness-script.py + $(P) $(CXX) -DGUI=0 -O -s -o $@ $< # Other targets else -TARGETS += $(PROGRAM_PREFIX)yosys-smtbmc +TARGETS += $(PROGRAM_PREFIX)yosys-smtbmc $(PROGRAM_PREFIX)yosys-witness $(PROGRAM_PREFIX)yosys-smtbmc: backends/smt2/smtbmc.py $(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/$(PROGRAM_PREFIX)yosys/python3"]]|;' < $< > $@.new $(Q) chmod +x $@.new $(Q) mv $@.new $@ + +$(PROGRAM_PREFIX)yosys-witness: backends/smt2/witness.py + $(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/$(PROGRAM_PREFIX)yosys/python3"]]|;' < $< > $@.new + $(Q) chmod +x $@.new + $(Q) mv $@.new $@ endif $(eval $(call add_share_file,share/python3,backends/smt2/smtio.py)) +$(eval $(call add_share_file,share/python3,backends/smt2/ywio.py)) endif endif diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index e6729aade..54783cf1b 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -23,6 +23,7 @@ #include "kernel/celltypes.h" #include "kernel/log.h" #include "kernel/mem.h" +#include "libs/json11/json11.hpp" #include USING_YOSYS_NAMESPACE @@ -588,6 +589,9 @@ struct Smt2Worker if (cell->type.in(ID($ff), ID($dff))) { registers.insert(cell); + for (auto chunk : cell->getPort(ID::Q).chunks()) + if (chunk.is_wire()) + decls.push_back(witness_signal("reg", chunk.width, chunk.offset, "", idcounter, chunk.wire)); makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(cell->getPort(ID::Q)), log_signal(cell->getPort(ID::Q))); register_bv(cell->getPort(ID::Q), idcounter++); recursive_cells.erase(cell); @@ -610,6 +614,12 @@ struct Smt2Worker decls.push_back(stringf("; yosys-smt2-minimize %s#%d\n", get_id(module), idcounter)); log("Wire %s is minimized\n", cell->getPort(QY).as_wire()->name.str().c_str()); } + + bool init_only = cell->type.in(ID($anyconst), ID($anyinit), ID($allconst)); + for (auto chunk : cell->getPort(QY).chunks()) + if (chunk.is_wire()) + decls.push_back(witness_signal(init_only ? "init" : "seq", chunk.width, chunk.offset, "", idcounter, chunk.wire)); + makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(cell->getPort(QY)), log_signal(cell->getPort(QY))); if (cell->type == ID($anyseq)) ex_input_eq.push_back(stringf(" (= (|%s#%d| state) (|%s#%d| other_state))", get_id(module), idcounter, get_id(module), idcounter)); @@ -760,6 +770,7 @@ struct Smt2Worker log_error("Memory %s.%s has mixed clocked/nonclocked write ports. This is not supported by \"write_smt2\".\n", log_id(cell), log_id(module)); decls.push_back(stringf("; yosys-smt2-memory %s %d %d %d %d %s\n", get_id(mem->memid), abits, mem->width, GetSize(mem->rd_ports), GetSize(mem->wr_ports), has_async_wr ? "async" : "sync")); + decls.push_back(witness_memory(get_id(mem->memid), cell, mem)); string memstate; if (has_async_wr) { @@ -852,6 +863,7 @@ struct Smt2Worker if (m != nullptr) { decls.push_back(stringf("; yosys-smt2-cell %s %s\n", get_id(cell->type), get_id(cell->name))); + decls.push_back(witness_cell(get_id(cell->name), cell)); string cell_state = stringf("(|%s_h %s| state)", get_id(module), get_id(cell->name)); for (auto &conn : cell->connections()) @@ -950,14 +962,19 @@ struct Smt2Worker for (auto wire : module->wires()) { bool is_register = false; - for (auto bit : SigSpec(wire)) + bool contains_clock = false; + for (auto bit : SigSpec(wire)) { if (reg_bits.count(bit)) is_register = true; + auto sig_bit = sigmap(bit); + if (clock_posedge.count(sig_bit) || clock_negedge.count(sig_bit)) + contains_clock = true; + } bool is_smtlib2_comb_expr = wire->has_attribute(ID::smtlib2_comb_expr); if (is_smtlib2_comb_expr && !is_smtlib2_module) log_error("smtlib2_comb_expr is only valid in a module with the smtlib2_module attribute: wire %s.%s", log_id(module), log_id(wire)); - if (wire->port_id || is_register || wire->get_bool_attribute(ID::keep) || (wiresmode && wire->name.isPublic())) { + if (wire->port_id || is_register || contains_clock || wire->get_bool_attribute(ID::keep) || (wiresmode && wire->name.isPublic())) { RTLIL::SigSpec sig = sigmap(wire); std::vector comments; if (wire->port_input) @@ -968,9 +985,20 @@ struct Smt2Worker comments.push_back(stringf("; yosys-smt2-register %s %d\n", get_id(wire), wire->width)); if (wire->get_bool_attribute(ID::keep) || (wiresmode && wire->name.isPublic())) comments.push_back(stringf("; yosys-smt2-wire %s %d\n", get_id(wire), wire->width)); - if (GetSize(wire) == 1 && (clock_posedge.count(sig) || clock_negedge.count(sig))) + if (contains_clock && GetSize(wire) == 1 && (clock_posedge.count(sig) || clock_negedge.count(sig))) comments.push_back(stringf("; yosys-smt2-clock %s%s%s\n", get_id(wire), clock_posedge.count(sig) ? " posedge" : "", clock_negedge.count(sig) ? " negedge" : "")); + if (contains_clock) { + for (int i = 0; i < GetSize(sig); i++) { + bool is_posedge = clock_posedge.count(sig[i]); + bool is_negedge = clock_negedge.count(sig[i]); + if (is_posedge != is_negedge) + comments.push_back(witness_signal( + is_posedge ? "posedge" : "negedge", 1, i, get_id(wire), -1, wire)); + } + } + if (wire->port_input) + comments.push_back(witness_signal("input", wire->width, 0, get_id(wire), -1, wire)); std::string smtlib2_comb_expr; if (is_smtlib2_comb_expr) { smtlib2_comb_expr = @@ -980,6 +1008,8 @@ struct Smt2Worker if (!bvmode && GetSize(sig) > 1) log_error("smtlib2_comb_expr is unsupported on multi-bit wires when -nobv is specified: wire %s.%s", log_id(module), log_id(wire)); + + comments.push_back(witness_signal("blackbox", wire->width, 0, get_id(wire), -1, wire)); } auto &out_decls = is_smtlib2_comb_expr ? smtlib2_decls : decls; if (bvmode && GetSize(sig) > 1) { @@ -1447,6 +1477,90 @@ struct Smt2Worker f << "true)"; f << stringf(" ; end of module %s\n", get_id(module)); } + + template static std::vector witness_path(T *obj) { + std::vector path; + if (obj->name.isPublic()) { + auto hdlname = obj->get_string_attribute(ID::hdlname); + for (auto token : split_tokens(hdlname)) + path.push_back("\\" + token); + } + if (path.empty()) + path.push_back(obj->name.str()); + return path; + } + + std::string witness_signal(const char *type, int width, int offset, const std::string &smtname, int smtid, RTLIL::Wire *wire) + { + std::vector hiername; + const char *wire_name = wire->name.c_str(); + if (wire_name[0] == '\\') { + auto hdlname = wire->get_string_attribute(ID::hdlname); + for (auto token : split_tokens(hdlname)) + hiername.push_back("\\" + token); + } + if (hiername.empty()) + hiername.push_back(wire->name.str()); + + std::string line = "; yosys-smt2-witness "; + (json11::Json { json11::Json::object { + { "type", type }, + { "offset", offset }, + { "width", width }, + { "smtname", smtname.empty() ? json11::Json(smtid) : json11::Json(smtname) }, + { "path", witness_path(wire) }, + }}).dump(line); + line += "\n"; + return line; + } + + std::string witness_cell(const char *smtname, RTLIL::Cell *cell) + { + std::string line = "; yosys-smt2-witness "; + (json11::Json {json11::Json::object { + { "type", "cell" }, + { "smtname", smtname }, + { "path", witness_path(cell) }, + }}).dump(line); + line += "\n"; + return line; + } + + std::string witness_memory(const char *smtname, RTLIL::Cell *cell, Mem *mem) + { + json11::Json::array uninitialized; + auto init_data = mem->get_init_data(); + + int cursor = 0; + + while (cursor < init_data.size()) { + while (cursor < init_data.size() && init_data[cursor] != State::Sx) + cursor++; + int offset = cursor; + while (cursor < init_data.size() && init_data[cursor] == State::Sx) + cursor++; + int width = cursor - offset; + if (width) + uninitialized.push_back(json11::Json::object { + {"width", width}, + {"offset", offset}, + }); + } + + std::string line = "; yosys-smt2-witness "; + (json11::Json { json11::Json::object { + { "type", "mem" }, + { "width", mem->width }, + { "size", mem->size }, + { "rom", mem->wr_ports.empty() }, + { "statebv", statebv }, + { "smtname", smtname }, + { "uninitialized", uninitialized }, + { "path", witness_path(cell) }, + }}).dump(line); + line += "\n"; + return line; + } }; struct Smt2Backend : public Backend { diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index 137182f33..b8ea22aaf 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -17,9 +17,10 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -import os, sys, getopt, re +import os, sys, getopt, re, bisect ##yosys-sys-path## from smtio import SmtIo, SmtOpts, MkVcd +from ywio import ReadWitness, WriteWitness, WitnessValues from collections import defaultdict got_topt = False @@ -28,6 +29,8 @@ step_size = 1 num_steps = 20 append_steps = 0 vcdfile = None +inywfile = None +outywfile = None cexfile = None aimfile = None aiwfile = None @@ -94,6 +97,9 @@ def usage(): the AIGER witness file does not include the status and properties lines. + --yw + read a Yosys witness. + --btorwit read a BTOR witness. @@ -121,6 +127,9 @@ def usage(): (hint: use 'write_smt2 -wires' for maximum coverage of signals in generated VCD file) + --dump-yw + write trace as a Yosys witness trace + --dump-vlogtb write trace as Verilog test bench @@ -167,8 +176,8 @@ def usage(): try: opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igcm:", so.longopts + - ["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "btorwit=", "presat", - "dump-vcd=", "dump-vlogtb=", "vlogtb-top=", "dump-smtc=", "dump-all", "noinfo", "append=", + ["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "yw=", "btorwit=", "presat", + "dump-vcd=", "dump-yw=", "dump-vlogtb=", "vlogtb-top=", "dump-smtc=", "dump-all", "noinfo", "append=", "smtc-init", "smtc-top=", "noinit", "binary", "keep-going"]) except: usage() @@ -204,10 +213,14 @@ for o, a in opts: aiwfile = a + ".aiw" elif o == "--aig-noheader": aigheader = False + elif o == "--yw": + inywfile = a elif o == "--btorwit": btorwitfile = a elif o == "--dump-vcd": vcdfile = a + elif o == "--dump-yw": + outywfile = a elif o == "--dump-vlogtb": vlogtbfile = a elif o == "--vlogtb-top": @@ -602,6 +615,101 @@ if aimfile is not None: num_steps = max(num_steps, step+2) step += 1 +if inywfile is not None: + with open(inywfile, "r") as f: + inyw = ReadWitness(f) + + inits, seqs, clocks, mems = smt.hierwitness(topmod, allregs=True, blackbox=True) + + smt_wires = defaultdict(list) + smt_mems = defaultdict(list) + + for wire in inits + seqs: + smt_wires[wire["path"]].append(wire) + + for mem in mems: + smt_mems[mem["path"]].append(mem) + + addr_re = re.compile(r'\\\[[0-9]+\]$') + bits_re = re.compile(r'[01?]*$') + + for t, step in inyw.steps(): + present_signals, missing = step.present_signals(inyw.sigmap) + for sig in present_signals: + bits = step[sig] + if not bits_re.match(bits): + raise ValueError("unsupported bit value in Yosys witness file") + + sig_end = sig.offset + len(bits) + if sig.path in smt_wires: + for wire in smt_wires[sig.path]: + width, offset = wire["width"], wire["offset"] + + smt_bool = smt.net_width(topmod, wire["smtpath"]) == 1 + + offset = max(offset, 0) + + end = width + offset + common_offset = max(sig.offset, offset) + common_end = min(sig_end, end) + if common_end <= common_offset: + continue + + smt_expr = smt.net_expr(topmod, f"s{t}", wire["smtpath"]) + + if not smt_bool: + slice_high = common_end - offset - 1 + slice_low = common_offset - offset + smt_expr = "((_ extract %d %d) %s)" % (slice_high, slice_low, smt_expr) + + bit_slice = bits[len(bits) - (common_end - sig.offset):len(bits) - (common_offset - sig.offset)] + + if bit_slice.count("?") == len(bit_slice): + continue + + if smt_bool: + assert width == 1 + smt_constr = "(= %s %s)" % (smt_expr, "true" if bit_slice == "1" else "false") + else: + if "?" in bit_slice: + mask = bit_slice.replace("0", "1").replace("?", "0") + bit_slice = bit_slice.replace("?", "0") + smt_expr = "(bvand %s #b%s)" % (smt_expr, mask) + + smt_constr = "(= %s #b%s)" % (smt_expr, bit_slice) + + constr_assumes[t].append((inywfile, smt_constr)) + + if sig.memory_path: + if sig.memory_path in smt_mems: + for mem in smt_mems[sig.memory_path]: + width, size, bv = mem["width"], mem["size"], mem["statebv"] + + smt_expr = smt.net_expr(topmod, f"s{t}", mem["smtpath"]) + + if bv: + word_low = sig.memory_addr * width + word_high = word_low + width - 1 + smt_expr = "((_ extract %d %d) %s)" % (word_high, word_low, smt_expr) + else: + addr_width = (size - 1).bit_length() + addr_bits = f"{sig.memory_addr:0{addr_width}b}" + smt_expr = "(select %s #b%s )" % (smt_expr, addr_bits) + + if len(bits) < width: + slice_high = sig.offset + len(bits) - 1 + smt_expr = "((_ extract %d %d) %s)" % (slice_high, sig.offset, smt_expr) + + bit_slice = bits + + if "?" in bit_slice: + mask = bit_slice.replace("0", "1").replace("?", "0") + bit_slice = bit_slice.replace("?", "0") + smt_expr = "(bvand %s #b%s)" % (smt_expr, mask) + + smt_constr = "(= %s #b%s)" % (smt_expr, bit_slice) + constr_assumes[t].append((inywfile, smt_constr)) + if btorwitfile is not None: with open(btorwitfile, "r") as f: step = None @@ -699,128 +807,137 @@ if btorwitfile is not None: skip_steps = step num_steps = step+1 -def write_vcd_trace(steps_start, steps_stop, index): - filename = vcdfile.replace("%", index) - print_msg("Writing trace to VCD file: %s" % (filename)) +def collect_mem_trace_data(steps_start, steps_stop, vcd=None): + mem_trace_data = dict() - with open(filename, "w") as vcd_file: - vcd = MkVcd(vcd_file) - path_list = list() + for mempath in sorted(smt.hiermems(topmod)): + abits, width, rports, wports, asyncwr = smt.mem_info(topmod, mempath) - for netpath in sorted(smt.hiernets(topmod)): - hidden_net = False - for n in netpath: - if n.startswith("$"): - hidden_net = True - if not hidden_net: - edge = smt.net_clock(topmod, netpath) - if edge is None: - vcd.add_net([topmod] + netpath, smt.net_width(topmod, netpath)) - else: - vcd.add_clock([topmod] + netpath, edge) - path_list.append(netpath) - - mem_trace_data = dict() - for mempath in sorted(smt.hiermems(topmod)): - abits, width, rports, wports, asyncwr = smt.mem_info(topmod, mempath) + expr_id = list() + expr_list = list() + for i in range(steps_start, steps_stop): + for j in range(rports): + expr_id.append(('R', i-steps_start, j, 'A')) + expr_id.append(('R', i-steps_start, j, 'D')) + expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "R%dA" % j)) + expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "R%dD" % j)) + for j in range(wports): + expr_id.append(('W', i-steps_start, j, 'A')) + expr_id.append(('W', i-steps_start, j, 'D')) + expr_id.append(('W', i-steps_start, j, 'M')) + expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dA" % j)) + expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dD" % j)) + expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dM" % j)) + + rdata = list() + wdata = list() + addrs = set() + + for eid, edat in zip(expr_id, smt.get_list(expr_list)): + t, i, j, f = eid + + if t == 'R': + c = rdata + elif t == 'W': + c = wdata + else: + assert False - expr_id = list() - expr_list = list() - for i in range(steps_start, steps_stop): - for j in range(rports): - expr_id.append(('R', i-steps_start, j, 'A')) - expr_id.append(('R', i-steps_start, j, 'D')) - expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "R%dA" % j)) - expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "R%dD" % j)) - for j in range(wports): - expr_id.append(('W', i-steps_start, j, 'A')) - expr_id.append(('W', i-steps_start, j, 'D')) - expr_id.append(('W', i-steps_start, j, 'M')) - expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dA" % j)) - expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dD" % j)) - expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dM" % j)) - - rdata = list() - wdata = list() - addrs = set() - - for eid, edat in zip(expr_id, smt.get_list(expr_list)): - t, i, j, f = eid - - if t == 'R': - c = rdata - elif t == 'W': - c = wdata - else: - assert False + while len(c) <= i: + c.append(list()) + c = c[i] - while len(c) <= i: - c.append(list()) - c = c[i] + while len(c) <= j: + c.append(dict()) + c = c[j] - while len(c) <= j: - c.append(dict()) - c = c[j] + c[f] = smt.bv2bin(edat) - c[f] = smt.bv2bin(edat) + if f == 'A': + addrs.add(c[f]) - if f == 'A': - addrs.add(c[f]) + for addr in addrs: + tdata = list() + data = ["x"] * width + gotread = False - for addr in addrs: - tdata = list() - data = ["x"] * width - gotread = False + if len(wdata) == 0 and len(rdata) != 0: + wdata = [[]] * len(rdata) - if len(wdata) == 0 and len(rdata) != 0: - wdata = [[]] * len(rdata) + assert len(rdata) == len(wdata) - assert len(rdata) == len(wdata) + for i in range(len(wdata)): + if not gotread: + for j_data in rdata[i]: + if j_data["A"] == addr: + data = list(j_data["D"]) + gotread = True + break - for i in range(len(wdata)): - if not gotread: - for j_data in rdata[i]: - if j_data["A"] == addr: - data = list(j_data["D"]) - gotread = True - break + if gotread: + buf = data[:] + for ii in reversed(range(len(tdata))): + for k in range(width): + if tdata[ii][k] == "x": + tdata[ii][k] = buf[k] + else: + buf[k] = tdata[ii][k] - if gotread: - buf = data[:] - for ii in reversed(range(len(tdata))): - for k in range(width): - if tdata[ii][k] == "x": - tdata[ii][k] = buf[k] - else: - buf[k] = tdata[ii][k] + if not asyncwr: + tdata.append(data[:]) - if not asyncwr: - tdata.append(data[:]) + for j_data in wdata[i]: + if j_data["A"] != addr: + continue - for j_data in wdata[i]: - if j_data["A"] != addr: - continue + D = j_data["D"] + M = j_data["M"] - D = j_data["D"] - M = j_data["M"] + for k in range(width): + if M[k] == "1": + data[k] = D[k] - for k in range(width): - if M[k] == "1": - data[k] = D[k] + if asyncwr: + tdata.append(data[:]) - if asyncwr: - tdata.append(data[:]) + assert len(tdata) == len(rdata) - assert len(tdata) == len(rdata) + int_addr = int(addr, 2) - netpath = mempath[:] - netpath[-1] += "<%0*x>" % ((len(addr)+3) // 4, int(addr, 2)) + netpath = mempath[:] + if vcd: + netpath[-1] += "<%0*x>" % ((len(addr)+3) // 4, int_addr) vcd.add_net([topmod] + netpath, width) - for i in range(steps_start, steps_stop): - if i not in mem_trace_data: - mem_trace_data[i] = list() - mem_trace_data[i].append((netpath, "".join(tdata[i-steps_start]))) + for i in range(steps_start, steps_stop): + if i not in mem_trace_data: + mem_trace_data[i] = list() + mem_trace_data[i].append((netpath, int_addr, "".join(tdata[i-steps_start]))) + + return mem_trace_data + +def write_vcd_trace(steps_start, steps_stop, index): + filename = vcdfile.replace("%", index) + print_msg("Writing trace to VCD file: %s" % (filename)) + + with open(filename, "w") as vcd_file: + vcd = MkVcd(vcd_file) + path_list = list() + + for netpath in sorted(smt.hiernets(topmod)): + hidden_net = False + for n in netpath: + if n.startswith("$"): + hidden_net = True + if not hidden_net: + edge = smt.net_clock(topmod, netpath) + if edge is None: + vcd.add_net([topmod] + netpath, smt.net_width(topmod, netpath)) + else: + vcd.add_clock([topmod] + netpath, edge) + path_list.append(netpath) + + mem_trace_data = collect_mem_trace_data(steps_start, steps_stop, vcd) for i in range(steps_start, steps_stop): vcd.set_time(i) @@ -828,7 +945,7 @@ def write_vcd_trace(steps_start, steps_stop, index): for path, value in zip(path_list, value_list): vcd.set_net([topmod] + path, value) if i in mem_trace_data: - for path, value in mem_trace_data[i]: + for path, addr, value in mem_trace_data[i]: vcd.set_net([topmod] + path, value) vcd.set_time(steps_stop) @@ -1072,8 +1189,72 @@ def write_constr_trace(steps_start, steps_stop, index): for name, val in zip(pi_names, pi_values): print("assume (= [%s%s] %s)" % (constr_prefix, ".".join(name), val), file=f) +def write_yw_trace(steps_start, steps_stop, index, allregs=False): + filename = outywfile.replace("%", index) + print_msg("Writing trace to Yosys witness file: %s" % (filename)) + + mem_trace_data = collect_mem_trace_data(steps_start, steps_stop) + + with open(filename, "w") as f: + inits, seqs, clocks, mems = smt.hierwitness(topmod, allregs) + + yw = WriteWitness(f, "smtbmc") + + for clock in clocks: + yw.add_clock(clock["path"], clock["offset"], clock["type"]) + + for seq in seqs: + seq["sig"] = yw.add_sig(seq["path"], seq["offset"], seq["width"]) + + for init in inits: + init["sig"] = yw.add_sig(init["path"], init["offset"], init["width"], True) + + inits = seqs + inits + + mem_dict = {tuple(mem["smtpath"]): mem for mem in mems} + mem_init_values = [] + + for path, addr, value in mem_trace_data.get(0, ()): + json_mem = mem_dict.get(tuple(path)) + if not json_mem: + continue + + bit_addr = addr * json_mem["width"] + uninit_chunks = [(chunk["width"] + chunk["offset"], chunk["offset"]) for chunk in json_mem["uninitialized"]] + first_chunk_nr = bisect.bisect_left(uninit_chunks, (bit_addr + 1,)) -def write_trace(steps_start, steps_stop, index): + for uninit_end, uninit_offset in uninit_chunks[first_chunk_nr:]: + assert uninit_end > bit_addr + if uninit_offset > bit_addr + json_mem["width"]: + break + + word_path = (*json_mem["path"], f"\\[{addr}]") + + overlap_start = max(uninit_offset - bit_addr, 0) + overlap_end = min(uninit_end - bit_addr, json_mem["width"]) + overlap_bits = value[len(value)-overlap_end:len(value)-overlap_start] + + sig = yw.add_sig(word_path, overlap_start, overlap_end - overlap_start, True) + mem_init_values.append((sig, overlap_bits.replace("x", "?"))) + + for k in range(steps_start, steps_stop): + step_values = WitnessValues() + + if k == steps_start: + for sig, value in mem_init_values: + step_values[sig] = value + sigs = inits + seqs + else: + sigs = seqs + + for sig in sigs: + step_values[sig["sig"]] = smt.bv2bin(smt.get(smt.net_expr(topmod, f"s{k}", sig["smtpath"]))) + yw.step(step_values) + + yw.end_trace() + + +def write_trace(steps_start, steps_stop, index, allregs=False): if vcdfile is not None: write_vcd_trace(steps_start, steps_stop, index) @@ -1083,6 +1264,9 @@ def write_trace(steps_start, steps_stop, index): if outconstr is not None: write_constr_trace(steps_start, steps_stop, index) + if outywfile is not None: + write_yw_trace(steps_start, steps_stop, index, allregs) + def print_failed_asserts_worker(mod, state, path, extrainfo, infomap, infokey=()): assert mod in smt.modinfo @@ -1392,12 +1576,12 @@ if tempind: print_msg("Temporal induction failed!") print_anyconsts(num_steps) print_failed_asserts(num_steps) - write_trace(step, num_steps+1, '%') + write_trace(step, num_steps+1, '%', allregs=True) elif dumpall: print_anyconsts(num_steps) print_failed_asserts(num_steps) - write_trace(step, num_steps+1, "%d" % step) + write_trace(step, num_steps+1, "%d" % step, allregs=True) else: print_msg("Temporal induction successful.") diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py index 3ba43825c..de09c040e 100644 --- a/backends/smt2/smtio.py +++ b/backends/smt2/smtio.py @@ -16,7 +16,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -import sys, re, os, signal +import sys, re, os, signal, json import subprocess if os.name == "posix": import resource @@ -108,6 +108,7 @@ class SmtModInfo: self.allconsts = dict() self.allseqs = dict() self.asize = dict() + self.witness = [] class SmtIo: @@ -587,6 +588,11 @@ class SmtIo: self.modinfo[self.curmod].allseqs[fields[2]] = (fields[4], None if len(fields) <= 5 else fields[5]) self.modinfo[self.curmod].asize[fields[2]] = int(fields[3]) + if fields[1] == "yosys-smt2-witness": + data = json.loads(stmt.split(None, 2)[2]) + if data.get("type") in ["cell", "mem", "posedge", "negedge", "input", "reg", "init", "seq", "blackbox"]: + self.modinfo[self.curmod].witness.append(data) + def hiernets(self, top, regs_only=False): def hiernets_worker(nets, mod, cursor): for netname in sorted(self.modinfo[mod].wsize.keys()): @@ -658,6 +664,57 @@ class SmtIo: hiermems_worker(mems, top, []) return mems + def hierwitness(self, top, allregs=False, blackbox=True): + init_witnesses = [] + seq_witnesses = [] + clk_witnesses = [] + mem_witnesses = [] + + def absolute(path, cursor, witness): + return { + **witness, + "path": path + tuple(witness["path"]), + "smtpath": cursor + [witness["smtname"]], + } + + for witness in self.modinfo[top].witness: + if witness["type"] == "input": + seq_witnesses.append(absolute((), [], witness)) + if witness["type"] in ("posedge", "negedge"): + clk_witnesses.append(absolute((), [], witness)) + + init_types = ["init"] + if allregs: + init_types.append("reg") + + seq_types = ["seq"] + if blackbox: + seq_types.append("blackbox") + + def worker(mod, path, cursor): + cell_paths = {} + for witness in self.modinfo[mod].witness: + if witness["type"] in init_types: + init_witnesses.append(absolute(path, cursor, witness)) + if witness["type"] in seq_types: + seq_witnesses.append(absolute(path, cursor, witness)) + if witness["type"] == "mem": + if allregs and not witness["rom"]: + width, size = witness["width"], witness["size"] + witness = {**witness, "uninitialized": {"width": width * size, "offset": 0}} + if not witness["uninitialized"]: + continue + + mem_witnesses.append(absolute(path, cursor, witness)) + if witness["type"] == "cell": + cell_paths[witness["smtname"]] = tuple(witness["path"]) + + for cellname, celltype in sorted(self.modinfo[mod].cells.items()): + worker(celltype, path + cell_paths.get(cellname, ("?" + cellname,)), cursor + [cellname]) + + worker(top, (), []) + return init_witnesses, seq_witnesses, clk_witnesses, mem_witnesses + def read(self): stmt = [] count_brackets = 0 @@ -887,6 +944,8 @@ class SmtIo: assert mod in self.modinfo if path[0] == "": return base + if isinstance(path[0], int): + return "(|%s#%d| %s)" % (mod, path[0], base) if path[0] in self.modinfo[mod].cells: return "(|%s_h %s| %s)" % (mod, path[0], base) if path[0] in self.modinfo[mod].wsize: @@ -909,6 +968,8 @@ class SmtIo: mod = self.modinfo[mod].cells[net_path[i]] assert mod in self.modinfo + if isinstance(net_path[-1], int): + return None assert net_path[-1] in self.modinfo[mod].wsize return self.modinfo[mod].wsize[net_path[-1]] diff --git a/backends/smt2/witness.py b/backends/smt2/witness.py new file mode 100644 index 000000000..1105d9ed0 --- /dev/null +++ b/backends/smt2/witness.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 +# +# 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. +# + +import os, sys +##yosys-sys-path## +import click + +from ywio import ReadWitness, WriteWitness, WitnessSig + +@click.group() +def cli(): + pass + + +@cli.command(help=""" +Display a Yosys witness trace in a human readable format. +""") +@click.argument("input", type=click.File("r")) +def display(input): + click.echo(f"Reading Yosys witness trace {input.name!r}...") + inyw = ReadWitness(input) + + def output(): + + yield click.style("*** RTLIL bit-order below may differ from source level declarations ***", fg="red") + if inyw.clocks: + yield click.style("=== Clock Signals ===", fg="blue") + for clock in inyw.clocks: + yield f" {clock['edge']} {WitnessSig(clock['path'], clock['offset']).pretty()}" + + for t, values in inyw.steps(): + if t: + yield click.style(f"=== Step {t} ===", fg="blue") + else: + yield click.style("=== Initial State ===", fg="blue") + + step_prefix = click.style(f"#{t}", fg="bright_black") + + signals, missing = values.present_signals(inyw.sigmap) + + assert not missing + + for sig in signals: + display_bits = values[sig].replace("?", click.style("?", fg="bright_black")) + yield f" {step_prefix} {sig.pretty()} = {display_bits}" + click.echo_via_pager([line + "\n" for line in output()]) + +@cli.command(help=""" +Transform a Yosys witness trace. + +Currently no transformations are implemented, so it is only useful for testing. +""") +@click.argument("input", type=click.File("r")) +@click.argument("output", type=click.File("w")) +def yw2yw(input, output): + click.echo(f"Copying yosys witness trace from {input.name!r} to {output.name!r}...") + inyw = ReadWitness(input) + outyw = WriteWitness(output, "yosys-witness yw2yw") + + for clock in inyw.clocks: + outyw.add_clock(clock["path"], clock["offset"], clock["edge"]) + + for sig in inyw.signals: + outyw.add_sig(sig.path, sig.offset, sig.width, sig.init_only) + + for t, values in inyw.steps(): + outyw.step(values) + + outyw.end_trace() + + click.echo(f"Copied {outyw.t + 1} time steps.") + +if __name__ == "__main__": + cli() diff --git a/backends/smt2/ywio.py b/backends/smt2/ywio.py new file mode 100644 index 000000000..8469b4162 --- /dev/null +++ b/backends/smt2/ywio.py @@ -0,0 +1,392 @@ +# +# 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. +# + +import json, re + +from functools import total_ordering + + +class PrettyJson: + def __init__(self, f): + self.f = f + self.indent = 0 + self.state = ["value"] + + def line(self): + indent = len(self.state) - bool(self.state and self.state[-1] == "value") + print("\n", end=" " * (2 * indent), file=self.f) + + def raw(self, str): + print(end=str, file=self.f) + + def begin_object(self): + self.begin_value() + self.raw("{") + self.state.append("object_first") + + def begin_array(self): + self.begin_value() + self.raw("[") + self.state.append("array_first") + + def end_object(self): + state = self.state.pop() + if state == "object": + self.line() + else: + assert state == "object_first" + self.raw("}") + self.end_value() + + def end_array(self): + state = self.state.pop() + if state == "array": + self.line() + else: + assert state == "array_first" + self.raw("]") + self.end_value() + + def name(self, name): + if self.state[-1] == "object_first": + self.state[-1] = "object" + else: + self.raw(",") + self.line() + json.dump(str(name), self.f) + self.raw(": ") + self.state.append("value") + + def begin_value(self): + if self.state[-1] == "array_first": + self.line() + self.state[-1] = "array" + elif self.state[-1] == "array": + self.raw(",") + self.line() + else: + assert self.state.pop() == "value" + + def end_value(self): + if not self.state: + print(file=self.f, flush=True) + + def value(self, value): + self.begin_value() + json.dump(value, self.f) + self.end_value() + + def entry(self, name, value): + self.name(name) + self.value(value) + + def object(self, entries=None): + if isinstance(entries, dict): + entries = dict.items() + self.begin_object() + for name, value in entries: + self.entry(name, value) + self.end_object() + + def array(self, values=None): + self.begin_array() + for value in values: + self.value(value) + self.end_array() + + +addr_re = re.compile(r'\\\[[0-9]+\]$') +public_name_re = re.compile(r"\\([a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?|\[[0-9]+\])$") + +def pretty_name(id): + if public_name_re.match(id): + return id.lstrip("\\") + else: + return id + +def pretty_path(path): + out = "" + for name in path: + name = pretty_name(name) + if name.startswith("["): + out += name + continue + if out: + out += "." + if name.startswith("\\") or name.startswith("$"): + out += name + " " + else: + out += name + + return out + +@total_ordering +class WitnessSig: + def __init__(self, path, offset, width=1, init_only=False): + path = tuple(path) + self.path, self.width, self.offset, self.init_only = path, width, offset, init_only + + self.memory_path = None + self.memory_addr = None + + sort_path = path + sort_id = -1 + if path and addr_re.match(path[-1]): + self.memory_path = sort_path = path[:-1] + self.memory_addr = sort_id = int(path[-1][2:-1]) + + self.sort_key = (init_only, sort_path, sort_id, offset, width) + + def bits(self): + return ((self.path, i) for i in range(self.offset, self.offset + self.width)) + + def rev_bits(self): + return ((self.path, i) for i in reversed(range(self.offset, self.offset + self.width))) + + def pretty(self): + if self.width > 1: + last_offset = self.offset + self.width - 1 + return f"{pretty_path(self.path)}[{last_offset}:{self.offset}]" + else: + return f"{pretty_path(self.path)}[{self.offset}]" + + def __eq__(self): + return self.sort_key + + def __hash__(self): + return hash(self.sort_key) + + def __lt__(self, other): + return self.sort_key < other.sort_key + + +def coalesce_signals(signals): + bits = {} + for sig in signals: + for bit in sig.bits(): + if sig.init_only: + bits.setdefault(bit, False) + else: + bits[bit] = True + + active = None + + out = [] + + for bit, not_init in sorted(bits.items()): + if active: + if active[0] == bit[0] and active[2] == bit[1] and active[3] == not_init: + active[2] += 1 + else: + out.append(WitnessSig(active[0], active[1], active[2] - active[1], not active[3])) + active = None + + if active is None: + active = [bit[0], bit[1], bit[1] + 1, not_init] + + if active: + out.append(WitnessSig(active[0], active[1], active[2] - active[1], not active[3])) + + return sorted(out) + + +class WitnessSigMap: + def __init__(self, signals=[]): + self.signals = [] + + self.id_to_bit = [] + self.bit_to_id = {} + self.bit_to_sig = {} + + for sig in signals: + self.add_signal(sig) + + def add_signal(self, sig): + self.signals.append(sig) + for bit in sig.bits(): + self.add_bit(bit) + self.bit_to_sig[bit] = sig + + def add_bit(self, bit, id=None): + if id is None: + id = len(self.id_to_bit) + self.id_to_bit.append(bit) + else: + if len(self.id_to_bit) <= id: + self.id_to_bit += [None] * (id - len(self.id_to_bit) + 1) + self.id_to_bit[id] = bit + self.bit_to_id[bit] = id + + +class WitnessValues: + def __init__(self): + self.values = {} + + def __setitem__(self, key, value): + if isinstance(key, tuple) and len(key) == 2: + if value != "?": + assert isinstance(value, str) + assert len(value) == 1 + self.values[key] = value + else: + assert isinstance(key, WitnessSig) + assert key.width == len(value) + if isinstance(value, str): + value = reversed(value) + for bit, bit_value in zip(key.bits(), value): + if bit_value != "?": + self.values[bit] = bit_value + + def __getitem__(self, key): + if isinstance(key, tuple) and len(key) == 2: + return self.values.get(key, "?") + else: + assert isinstance(key, WitnessSig) + return "".join([self.values.get(bit, "?") for bit in key.rev_bits()]) + + def pack_present(self, sigmap): + missing = [] + + max_id = max((sigmap.bit_to_id.get(bit, -1) for bit in self.values), default=-1) + + vector = ["?"] * (max_id + 1) + for bit, bit_value in self.values.items(): + id = sigmap.bit_to_id.get(bit, - 1) + if id < 0: + missing.append(bit) + else: + vector[max_id - sigmap.bit_to_id[bit]] = bit_value + + return "".join(vector), missing + + def pack(self, sigmap): + packed, missing = self.pack_present(sigmap) + if missing: + raise RuntimeError(f"Cannot pack bits {missing!r}") + return packed + + def unpack(self, sigmap, bits): + for i, bit_value in enumerate(reversed(bits)): + if bit_value != "?": + self.values[sigmap.id_to_bit[i]] = bit_value + + def present_signals(self, sigmap): + signals = set(sigmap.bit_to_sig.get(bit) for bit in self.values) + missing_signals = None in signals + if missing_signals: + signals.discard(None) + + return sorted(signals), missing_signals + + +class WriteWitness: + def __init__(self, f, generator): + self.out = PrettyJson(f) + self.t = 0 + self.header_written = False + self.clocks = [] + self.signals = [] + + self.out.begin_object() + self.out.entry("format", "Yosys Witness Trace") + self.out.entry("generator", generator) + + def add_clock(self, path, offset, edge): + assert not self.header_written + self.clocks.append({ + "path": path, + "edge": edge, + "offset": offset, + }) + + def add_sig(self, path, offset, width=1, init_only=False): + assert not self.header_written + sig = WitnessSig(path, offset, width, init_only) + self.signals.append(sig) + return sig + + def write_header(self): + assert not self.header_written + self.header_written = True + self.out.name("clocks") + self.out.array(self.clocks) + + self.signals = coalesce_signals(self.signals) + self.sigmap = WitnessSigMap(self.signals) + + self.out.name("signals") + self.out.array({ + "path": sig.path, + "width": sig.width, + "offset": sig.offset, + "init_only": sig.init_only, + } for sig in self.signals) + + self.out.name("steps") + self.out.begin_array() + + def step(self, values): + if not self.header_written: + self.write_header() + + self.out.value({"bits": values.pack(self.sigmap)}) + + self.t += 1 + + def end_trace(self): + if not self.header_written: + self.write_header() + self.out.end_array() + self.out.end_object() + + +class ReadWitness: + def __init__(self, f): + data = json.load(f) + if not isinstance(data, dict): + data = {} + + data_format = data.get("format", "Unknown Format") + + if data_format != "Yosys Witness Trace": + raise ValueError(f"unsupported format {data_format!r}") + + self.clocks = data["clocks"] + for clock in self.clocks: + clock["path"] = tuple(clock["path"]) + + self.signals = [ + WitnessSig(sig["path"], sig["offset"], sig["width"], sig["init_only"]) + for sig in data["signals"] + ] + + self.sigmap = WitnessSigMap(self.signals) + + self.bits = [step["bits"] for step in data["steps"]] + + def step(self, t): + values = WitnessValues() + values.unpack(self.sigmap, self.bits[t]) + return values + + def steps(self): + for i in range(len(self.bits)): + yield i, self.step(i) + + def __len__(self): + return len(self.bits) diff --git a/tests/various/smtlib2_module-expected.smt2 b/tests/various/smtlib2_module-expected.smt2 index ace858ca8..74e2f3fca 100644 --- a/tests/various/smtlib2_module-expected.smt2 +++ b/tests/various/smtlib2_module-expected.smt2 @@ -4,11 +4,14 @@ (declare-fun |smtlib2_is| (|smtlib2_s|) Bool) (declare-fun |smtlib2#0| (|smtlib2_s|) (_ BitVec 8)) ; \a ; yosys-smt2-input a 8 +; yosys-smt2-witness {"offset": 0, "path": ["\\a"], "smtname": "a", "type": "input", "width": 8} (define-fun |smtlib2_n a| ((state |smtlib2_s|)) (_ BitVec 8) (|smtlib2#0| state)) (declare-fun |smtlib2#1| (|smtlib2_s|) (_ BitVec 8)) ; \b ; yosys-smt2-input b 8 +; yosys-smt2-witness {"offset": 0, "path": ["\\b"], "smtname": "b", "type": "input", "width": 8} (define-fun |smtlib2_n b| ((state |smtlib2_s|)) (_ BitVec 8) (|smtlib2#1| state)) ; yosys-smt2-output add 8 +; yosys-smt2-witness {"offset": 0, "path": ["\\add"], "smtname": "add", "type": "blackbox", "width": 8} (define-fun |smtlib2_n add| ((state |smtlib2_s|)) (_ BitVec 8) (let ( (|a| (|smtlib2_n a| state)) (|b| (|smtlib2_n b| state)) @@ -16,6 +19,7 @@ (bvadd a b) )) ; yosys-smt2-output eq 1 +; yosys-smt2-witness {"offset": 0, "path": ["\\eq"], "smtname": "eq", "type": "blackbox", "width": 1} (define-fun |smtlib2_n eq| ((state |smtlib2_s|)) Bool (let ( (|a| (|smtlib2_n a| state)) (|b| (|smtlib2_n b| state)) @@ -23,6 +27,7 @@ (= a b) )) ; yosys-smt2-output sub 8 +; yosys-smt2-witness {"offset": 0, "path": ["\\sub"], "smtname": "sub", "type": "blackbox", "width": 8} (define-fun |smtlib2_n sub| ((state |smtlib2_s|)) (_ BitVec 8) (let ( (|a| (|smtlib2_n a| state)) (|b| (|smtlib2_n b| state)) @@ -38,13 +43,16 @@ (declare-sort |uut_s| 0) (declare-fun |uut_is| (|uut_s|) Bool) ; yosys-smt2-cell smtlib2 s +; yosys-smt2-witness {"path": ["\\s"], "smtname": "s", "type": "cell"} (declare-fun |uut#0| (|uut_s|) (_ BitVec 8)) ; \add (declare-fun |uut#1| (|uut_s|) Bool) ; \eq (declare-fun |uut#2| (|uut_s|) (_ BitVec 8)) ; \sub (declare-fun |uut_h s| (|uut_s|) |smtlib2_s|) ; yosys-smt2-anyconst uut#3 8 smtlib2_module.v:14.17-14.26 +; yosys-smt2-witness {"offset": 0, "path": ["\\a"], "smtname": 3, "type": "init", "width": 8} (declare-fun |uut#3| (|uut_s|) (_ BitVec 8)) ; \a ; yosys-smt2-anyconst uut#4 8 smtlib2_module.v:14.32-14.41 +; yosys-smt2-witness {"offset": 0, "path": ["\\b"], "smtname": 4, "type": "init", "width": 8} (declare-fun |uut#4| (|uut_s|) (_ BitVec 8)) ; \b (define-fun |uut#5| ((state |uut_s|)) (_ BitVec 8) (bvadd (|uut#3| state) (|uut#4| state))) ; \add2 (define-fun |uut#6| ((state |uut_s|)) Bool (= (|uut#0| state) (|uut#5| state))) ; $0$formal$smtlib2_module.v:28$1_CHECK[0:0]$9 -- cgit v1.2.3 From efd5b86eb9c56d293c608d378ee90beea53784b5 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 2 Aug 2022 17:02:39 +0200 Subject: aiger: Add yosys-witness support Adds a new json based aiger map file and yosys-witness converters to us this to convert between native and AIGER witness files. --- CHANGELOG | 3 + backends/aiger/aiger.cc | 169 +++++++++++++++++++++++++++++++++++++++++++++++ backends/smt2/witness.py | 150 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 320 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index cf2a46bd3..a9144facf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,6 +15,9 @@ Yosys 0.20 .. Yosys 0.20-dev - yosys-smtbmc: Reading and writing of yosys witness traces. - write_smt2: Emit inline metadata to support yosys witness trace. - yosys-witness is a new tool to inspect and convert yosys witness traces. + - write_aiger: Option to write a map file for yosys witness trace + conversion. + - yosys-witness: Conversion from and to AIGER witness traces. Yosys 0.19 .. Yosys 0.20 -------------------------- diff --git a/backends/aiger/aiger.cc b/backends/aiger/aiger.cc index 800743b22..2ea999dc0 100644 --- a/backends/aiger/aiger.cc +++ b/backends/aiger/aiger.cc @@ -19,6 +19,7 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" +#include "libs/json11/json11.hpp" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -61,6 +62,8 @@ struct AigerWriter dict init_inputs; int initstate_ff = 0; + dict ywmap_clocks; + int mkgate(int a0, int a1) { aig_m++, aig_a++; @@ -159,6 +162,17 @@ struct AigerWriter output_bits.insert(wirebit); } } + + if (wire->width == 1) { + auto gclk_attr = wire->attributes.find(ID::replaced_by_gclk); + if (gclk_attr != wire->attributes.end()) { + SigBit bit = sigmap(wire); + if (gclk_attr->second == State::S1) + ywmap_clocks[bit] |= 1; + else if (gclk_attr->second == State::S0) + ywmap_clocks[bit] |= 2; + } + } } for (auto bit : input_bits) @@ -186,6 +200,11 @@ struct AigerWriter unused_bits.erase(D); undriven_bits.erase(Q); ff_map[Q] = D; + + if (cell->type != ID($_FF_)) { + auto sig_clk = sigmap(cell->getPort(ID::CLK).as_bit()); + ywmap_clocks[sig_clk] |= cell->type == ID($_DFF_N_) ? 2 : 1; + } continue; } @@ -689,6 +708,137 @@ struct AigerWriter for (auto &it : wire_lines) f << it.second; } + + template static std::vector witness_path(T *obj) { + std::vector path; + if (obj->name.isPublic()) { + auto hdlname = obj->get_string_attribute(ID::hdlname); + for (auto token : split_tokens(hdlname)) + path.push_back("\\" + token); + } + if (path.empty()) + path.push_back(obj->name.str()); + return path; + } + + void write_ywmap(std::ostream &f) + { + f << "{\n"; + f << " \"version\": \"Yosys Witness Aiger Map\",\n"; + f << stringf(" \"generator\": %s,\n", json11::Json(yosys_version_str).dump().c_str()); + f << stringf(" \"latch_count\": %d,\n", aig_l); + f << stringf(" \"input_count\": %d,\n", aig_i); + + dict clock_lines; + dict input_lines; + dict init_lines; + dict seq_lines; + + for (auto cell : module->cells()) + { + if (cell->type.in(ID($_FF_), ID($_DFF_N_), ID($_DFF_P_), ID($anyinit), ID($anyconst), ID($anyseq))) + { + // Use sig_q to get the FF output name, but sig to lookup aiger bits + auto sig_qy = cell->getPort(cell->type.in(ID($anyconst), ID($anyseq)) ? ID::Y : ID::Q); + SigSpec sig = sigmap(sig_qy); + + for (int i = 0; i < GetSize(sig_qy); i++) { + if (sig_qy[i].wire == nullptr || sig[i].wire == nullptr) + continue; + + auto wire = sig_qy[i].wire; + + if (init_inputs.count(sig[i])) { + int a = init_inputs.at(sig[i]); + log_assert((a & 1) == 0); + init_lines[a] += json11::Json(json11::Json::object { + { "path", witness_path(wire) }, + { "input", (a >> 1) - 1 }, + { "offset", sig_qy[i].offset }, + }).dump(); + } + + if (input_bits.count(sig[i])) { + int a = aig_map.at(sig[i]); + log_assert((a & 1) == 0); + seq_lines[a] += json11::Json(json11::Json::object { + { "path", witness_path(wire) }, + { "input", (a >> 1) - 1 }, + { "offset", sig_qy[i].offset }, + }).dump(); + } + } + } + } + + for (auto wire : module->wires()) + { + SigSpec sig = sigmap(wire); + if (wire->port_input) + { + auto path = witness_path(wire); + for (int i = 0; i < GetSize(wire); i++) { + if (aig_map.count(sig[i]) == 0 || sig[i].wire == nullptr) + continue; + + int a = aig_map.at(sig[i]); + log_assert((a & 1) == 0); + input_lines[a] += json11::Json(json11::Json::object { + { "path", path }, + { "input", (a >> 1) - 1 }, + { "offset", i }, + }).dump(); + + if (ywmap_clocks.count(sig[i])) { + int clock_mode = ywmap_clocks[sig[i]]; + if (clock_mode != 3) { + clock_lines[a] += json11::Json(json11::Json::object { + { "path", path }, + { "input", (a >> 1) - 1 }, + { "offset", i }, + { "edge", clock_mode == 1 ? "posedge" : "negedge" }, + }).dump(); + } + } + } + } + } + + f << " \"clocks\": ["; + clock_lines.sort(); + const char *sep = "\n "; + for (auto &it : clock_lines) { + f << sep << it.second; + sep = ",\n "; + } + f << "\n ],\n"; + + f << " \"inputs\": ["; + input_lines.sort(); + sep = "\n "; + for (auto &it : input_lines) { + f << sep << it.second; + sep = ",\n "; + } + f << "\n ],\n"; + + f << " \"seqs\": ["; + sep = "\n "; + for (auto &it : seq_lines) { + f << sep << it.second; + sep = ",\n "; + } + f << "\n ],\n"; + + f << " \"inits\": ["; + sep = "\n "; + for (auto &it : init_lines) { + f << sep << it.second; + sep = ",\n "; + } + f << "\n ]\n}\n"; + } + }; struct AigerBackend : public Backend { @@ -728,6 +878,9 @@ struct AigerBackend : public Backend { log(" -no-startoffset\n"); log(" make indexes zero based, enable using map files with smt solvers.\n"); log("\n"); + log(" -ywmap \n"); + log(" write a map file for conversion to and from yosys witness traces.\n"); + log("\n"); log(" -I, -O, -B, -L\n"); log(" If the design contains no input/output/assert/flip-flop then create one\n"); log(" dummy input/output/bad_state-pin or latch to make the tools reading the\n"); @@ -747,6 +900,7 @@ struct AigerBackend : public Backend { bool lmode = false; bool no_startoffset = false; std::string map_filename; + std::string yw_map_filename; log_header(design, "Executing AIGER backend.\n"); @@ -778,6 +932,10 @@ struct AigerBackend : public Backend { verbose_map = true; continue; } + if (yw_map_filename.empty() && args[argidx] == "-ywmap" && argidx+1 < args.size()) { + yw_map_filename = args[++argidx]; + continue; + } if (args[argidx] == "-no-startoffset") { no_startoffset = true; continue; @@ -802,6 +960,9 @@ struct AigerBackend : public Backend { } extra_args(f, filename, args, argidx, !ascii_mode); + if (!yw_map_filename.empty() && !zinit_mode) + log_error("Currently -ywmap requires -zinit.\n"); + Module *top_module = design->top_module(); if (top_module == nullptr) @@ -826,6 +987,14 @@ struct AigerBackend : public Backend { log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno)); writer.write_map(mapf, verbose_map, no_startoffset); } + + if (!yw_map_filename.empty()) { + std::ofstream mapf; + mapf.open(yw_map_filename.c_str(), std::ofstream::trunc); + if (mapf.fail()) + log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno)); + writer.write_ywmap(mapf); + } } } AigerBackend; diff --git a/backends/smt2/witness.py b/backends/smt2/witness.py index 1105d9ed0..03d72a17b 100644 --- a/backends/smt2/witness.py +++ b/backends/smt2/witness.py @@ -17,11 +17,12 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -import os, sys +import os, sys, itertools, re ##yosys-sys-path## +import json import click -from ywio import ReadWitness, WriteWitness, WitnessSig +from ywio import ReadWitness, WriteWitness, WitnessSig, WitnessSigMap, WitnessValues, coalesce_signals @click.group() def cli(): @@ -86,5 +87,150 @@ def yw2yw(input, output): click.echo(f"Copied {outyw.t + 1} time steps.") + +class AigerMap: + def __init__(self, mapfile): + data = json.load(mapfile) + + self.latch_count = data["latch_count"] + self.input_count = data["input_count"] + + self.clocks = data["clocks"] + + self.sigmap = WitnessSigMap() + self.init_inputs = set(init["input"] for init in data["inits"]) + + for bit in data["inputs"] + data["seqs"] + data["inits"]: + self.sigmap.add_bit((tuple(bit["path"]), bit["offset"]), bit["input"]) + + + +@cli.command(help=""" +Convert an AIGER witness trace into a Yosys witness trace. + +This requires a Yosys witness AIGER map file as generated by 'write_aiger -ywmap'. +""") +@click.argument("input", type=click.File("r")) +@click.argument("mapfile", type=click.File("r")) +@click.argument("output", type=click.File("w")) +def aiw2yw(input, mapfile, output): + input_name = input.name + click.echo(f"Converting AIGER witness trace {input_name!r} to Yosys witness trace {output.name!r}...") + click.echo(f"Using Yosys witness AIGER map file {mapfile.name!r}") + aiger_map = AigerMap(mapfile) + + header_lines = list(itertools.islice(input, 0, 2)) + + if len(header_lines) == 2 and header_lines[1][0] in ".bcjf": + status = header_lines[0].strip() + if status == "0": + raise click.ClickException(f"{input_name}: file contains no trace, the AIGER status is unsat") + elif status == "2": + raise click.ClickException(f"{input_name}: file contains no trace, the AIGER status is sat") + elif status != "1": + raise click.ClickException(f"{input_name}: unexpected data in AIGER witness file") + else: + input = itertools.chain(header_lines, input) + + ffline = next(input, None) + if ffline is None: + raise click.ClickException(f"{input_name}: unexpected end of file") + ffline = ffline.strip() + if not re.match(r'[01x]*$', ffline): + raise click.ClickException(f"{input_name}: unexpected data in AIGER witness file") + if not re.match(r'[0]*$', ffline): + raise click.ClickException(f"{input_name}: non-default initial state not supported") + + outyw = WriteWitness(output, 'yosys-witness aiw2yw') + + for clock in aiger_map.clocks: + outyw.add_clock(clock["path"], clock["offset"], clock["edge"]) + + for (path, offset), id in aiger_map.sigmap.bit_to_id.items(): + outyw.add_sig(path, offset, init_only=id in aiger_map.init_inputs) + + missing = set() + + while True: + inline = next(input, None) + if inline is None: + click.echo(f"Warning: {input_name}: file may be incomplete") + break + inline = inline.strip() + if inline in [".", "# DONE"]: + break + if inline.startswith("#"): + continue + + if not re.match(r'[01x]*$', ffline): + raise click.ClickException(f"{input_name}: unexpected data in AIGER witness file") + + if len(inline) != aiger_map.input_count: + raise click.ClickException( + f"{input_name}: {mapfile.name}: number of inputs does not match, " + f"{len(inline)} in witness, {aiger_map.input_count} in map file") + + values = WitnessValues() + for i, v in enumerate(inline): + if v == "x" or outyw.t > 0 and i in aiger_map.init_inputs: + continue + + try: + bit = aiger_map.sigmap.id_to_bit[i] + except IndexError: + bit = None + if bit is None: + missing.insert(i) + + values[bit] = v + + outyw.step(values) + + outyw.end_trace() + + if missing: + click.echo("The following AIGER inputs belong to unknown signals:") + click.echo(" " + " ".join(str(id) for id in sorted(missing))) + + click.echo(f"Converted {outyw.t} time steps.") + +@cli.command(help=""" +Convert a Yosys witness trace into an AIGER witness trace. + +This requires a Yosys witness AIGER map file as generated by 'write_aiger -ywmap'. +""") +@click.argument("input", type=click.File("r")) +@click.argument("mapfile", type=click.File("r")) +@click.argument("output", type=click.File("w")) +def yw2aiw(input, mapfile, output): + click.echo(f"Converting Yosys witness trace {input.name!r} to AIGER witness trace {output.name!r}...") + click.echo(f"Using Yosys witness AIGER map file {mapfile.name!r}") + aiger_map = AigerMap(mapfile) + inyw = ReadWitness(input) + + print("1", file=output) + print("b0", file=output) + # TODO the b0 status isn't really accurate, but we don't have any better info here + print("0" * aiger_map.latch_count, file=output) + + all_missing = set() + + for t, step in inyw.steps(): + bits, missing = step.pack_present(aiger_map.sigmap) + bits = bits[::-1].replace('?', 'x') + all_missing.update(missing) + bits += 'x' * (aiger_map.input_count - len(bits)) + print(bits, file=output) + + print(".", file=output) + + if all_missing: + click.echo("The following signals are missing in the AIGER map file and will be dropped:") + for sig in coalesce_signals(WitnessSig(*bit) for bit in all_missing): + click.echo(" " + sig.pretty()) + + + click.echo(f"Converted {len(inyw)} time steps.") + if __name__ == "__main__": cli() -- cgit v1.2.3 From 475267ac254f6f5ec2202b58c26d8ea82c9d2e4a Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 2 Aug 2022 17:04:34 +0200 Subject: smtbmc: Add --check-witness mode This verifies that the given constraints force an assertion failure. This is useful to debug witness trace conversion (and minimization). --- backends/smt2/smtbmc.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index b8ea22aaf..3714e2918 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -54,6 +54,7 @@ smtctop = None noinit = False binarymode = False keep_going = False +check_witness = False so = SmtOpts() @@ -170,6 +171,10 @@ def usage(): covering all found failed assertions, the character '%' is replaced in all dump filenames with an increasing number. + --check-witness + check that the used witness file contains sufficient + constraints to force an assertion failure. + """ + so.helpmsg()) sys.exit(1) @@ -178,7 +183,7 @@ try: opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igcm:", so.longopts + ["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "yw=", "btorwit=", "presat", "dump-vcd=", "dump-yw=", "dump-vlogtb=", "vlogtb-top=", "dump-smtc=", "dump-all", "noinfo", "append=", - "smtc-init", "smtc-top=", "noinit", "binary", "keep-going"]) + "smtc-init", "smtc-top=", "noinit", "binary", "keep-going", "check-witness"]) except: usage() @@ -257,6 +262,8 @@ for o, a in opts: binarymode = True elif o == "--keep-going": keep_going = True + elif o == "--check-witness": + check_witness = True elif so.handle(o, a): pass else: @@ -1774,6 +1781,7 @@ else: # not tempind, covermode smt_assert("(not %s)" % active_assert_expr) else: + active_assert_expr = "true" smt_assert("false") @@ -1781,6 +1789,17 @@ else: # not tempind, covermode if retstatus != "FAILED": print("%s BMC failed!" % smt.timestamp()) + if check_witness: + print_msg("Checking witness constraints...") + smt_pop() + smt_push() + smt_assert(active_assert_expr) + if smt_check_sat() != "sat": + retstatus = "PASSED" + check_witness = False + num_steps = -1 + break + if append_steps > 0: for i in range(last_check_step+1, last_check_step+1+append_steps): print_msg("Appending additional step %d." % i) @@ -1873,6 +1892,8 @@ else: # not tempind, covermode print_anyconsts(0) write_trace(0, num_steps, '%') + if check_witness: + retstatus = "FAILED" smt.write("(exit)") smt.wait() -- cgit v1.2.3 From b156fe903f75b589cb270c062a5cbd65f55e5cf6 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Fri, 5 Aug 2022 15:24:28 +0200 Subject: yosys-witness: Add stats command --- backends/smt2/witness.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/backends/smt2/witness.py b/backends/smt2/witness.py index 03d72a17b..a1e65569d 100644 --- a/backends/smt2/witness.py +++ b/backends/smt2/witness.py @@ -62,6 +62,24 @@ def display(input): yield f" {step_prefix} {sig.pretty()} = {display_bits}" click.echo_via_pager([line + "\n" for line in output()]) + +@cli.command(help=""" +Display statistics of a Yosys witness trace. +""") +@click.argument("input", type=click.File("r")) +def stats(input): + click.echo(f"Reading Yosys witness trace {input.name!r}...") + inyw = ReadWitness(input) + + total = 0 + + for t, values in inyw.steps(): + click.echo(f"{t:5}: {len(values.values):8} bits") + total += len(values.values) + + click.echo(f"total: {total:8} bits") + + @cli.command(help=""" Transform a Yosys witness trace. -- cgit v1.2.3 From 65145db7e7bec998a194aa0f6335de50df00e550 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Wed, 3 Aug 2022 17:27:06 +0200 Subject: rename: Add -witness mode --- CHANGELOG | 2 ++ passes/cmds/rename.cc | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index a9144facf..6403c5b9a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ Yosys 0.20 .. Yosys 0.20-dev * New commands and options - Added "formalff" pass - transforms FFs for formal verification - Added option "-formal" to "memory_map" pass + - Added option "-witness" to "rename" - give public names to all signals + present in yosys witness traces * Formal Verification - Added $anyinit cell to directly represent FFs with an unconstrained diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc index b49d5cdc2..45576c91c 100644 --- a/passes/cmds/rename.cc +++ b/passes/cmds/rename.cc @@ -106,6 +106,60 @@ static IdString derive_name_from_cell_output_wire(const RTLIL::Cell *cell, strin return name + suffix; } +static bool rename_witness(RTLIL::Design *design, dict &cache, RTLIL::Module *module) +{ + auto cached = cache.find(module); + if (cached != cache.end()) { + if (cached->second == -1) + log_error("Cannot rename witness signals in a design containing recursive instantiations.\n"); + return cached->second; + } + cache.emplace(module, -1); + + bool has_witness_signals = false; + for (auto cell : module->cells()) + { + RTLIL::Module *impl = design->module(cell->type); + if (impl != nullptr) { + bool witness_in_cell = rename_witness(design, cache, impl); + has_witness_signals |= witness_in_cell; + if (witness_in_cell && !cell->name.isPublic()) { + std::string name = cell->name.c_str() + 1; + for (auto &c : name) + if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9') && c != '_') + c = '_'; + auto new_id = module->uniquify("\\_witness_." + name); + cell->set_hdlname_attribute({ "_witness_", strstr(new_id.c_str(), ".") + 1 }); + module->rename(cell, new_id); + } + } + + if (cell->type.in(ID($anyconst), ID($anyseq), ID($anyinit), ID($allconst), ID($allseq))) { + has_witness_signals = true; + auto QY = cell->type == ID($anyinit) ? ID::Q : ID::Y; + auto sig_out = cell->getPort(QY); + + for (auto chunk : sig_out.chunks()) { + if (chunk.is_wire() && !chunk.wire->name.isPublic()) { + std::string name = stringf("%s_%s", cell->type.c_str() + 1, cell->name.c_str() + 1); + for (auto &c : name) + if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9') && c != '_') + c = '_'; + auto new_id = module->uniquify("\\_witness_." + name); + auto new_wire = module->addWire(new_id, GetSize(sig_out)); + new_wire->set_hdlname_attribute({ "_witness_", strstr(new_id.c_str(), ".") + 1 }); + module->connect({sig_out, new_wire}); + cell->setPort(QY, new_wire); + break; + } + } + } + } + + cache[module] = has_witness_signals; + return has_witness_signals; +} + struct RenamePass : public Pass { RenamePass() : Pass("rename", "rename object in the design") { } void help() override @@ -147,6 +201,14 @@ struct RenamePass : public Pass { log("pattern is '_%%_'.\n"); log("\n"); log("\n"); + log(" rename -witness\n"); + log("\n"); + log("Assigns auto-generated names to all $any*/$all* output wires and containing\n"); + log("cells that do not have a public name. This ensures that, during formal\n"); + log("verification, a solver-found trace can be fully specified using a public\n"); + log("hierarchical names.\n"); + log("\n"); + log("\n"); log(" rename -hide [selection]\n"); log("\n"); log("Assign private names (the ones with $-prefix) to all selected wires and cells\n"); @@ -172,6 +234,7 @@ struct RenamePass : public Pass { bool flag_src = false; bool flag_wire = false; bool flag_enumerate = false; + bool flag_witness = false; bool flag_hide = false; bool flag_top = false; bool flag_output = false; @@ -203,6 +266,11 @@ struct RenamePass : public Pass { got_mode = true; continue; } + if (arg == "-witness" && !got_mode) { + flag_witness = true; + got_mode = true; + continue; + } if (arg == "-hide" && !got_mode) { flag_hide = true; got_mode = true; @@ -309,6 +377,19 @@ struct RenamePass : public Pass { } } else + if (flag_witness) + { + extra_args(args, argidx, design, false); + + RTLIL::Module *module = design->top_module(); + + if (module == nullptr) + log_cmd_error("No top module found!\n"); + + dict cache; + rename_witness(design, cache, module); + } + else if (flag_hide) { extra_args(args, argidx, design); -- cgit v1.2.3 From 4ad13c647e2789268aed06d528bc2a40c6196133 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Fri, 5 Aug 2022 15:34:14 +0200 Subject: clk2fflogic: Generate less unused logic when using verific Verific generates a lot of FFs with an unused async load and we cannot always optimize that away before running clk2fflogic, so check for that special case here. --- passes/sat/clk2fflogic.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/passes/sat/clk2fflogic.cc b/passes/sat/clk2fflogic.cc index b1b0567a0..2384ffced 100644 --- a/passes/sat/clk2fflogic.cc +++ b/passes/sat/clk2fflogic.cc @@ -233,7 +233,10 @@ struct Clk2fflogicPass : public Pass { qval = past_q; } - if (ff.has_aload) { + // The check for a constant sig_aload is also done by opt_dff, but when using verific and running + // clk2fflogic before opt_dff (which does more and possibly unwanted optimizations) this check avoids + // generating a lot of extra logic. + if (ff.has_aload && ff.sig_aload != (ff.pol_aload ? State::S0 : State::S1)) { SigSpec sig_aload = wrap_async_control(module, ff.sig_aload, ff.pol_aload, ff.is_fine, NEW_ID); if (!ff.is_fine) -- cgit v1.2.3 From 927af914f11f895d10475917d5c0b06261703362 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Fri, 5 Aug 2022 15:22:56 +0200 Subject: Update CEX minimization patches for abc --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b3a466a5e..4342882c3 100644 --- a/Makefile +++ b/Makefile @@ -155,7 +155,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 = 7cc11f7 +ABCREV = 20f970f ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) -- cgit v1.2.3 From 66f761a8c54b66b8e6b4667cfb54072ad76952e0 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Mon, 8 Aug 2022 15:33:47 +0200 Subject: smtbmc: Set step range for --yw and dont skip steps for --check-witness --- backends/smt2/smtbmc.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index 3714e2918..5f05287de 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -482,7 +482,8 @@ if cexfile is not None: constr_assumes[step].append((cexfile, smtexpr)) if not got_topt: - skip_steps = max(skip_steps, step) + if not check_witness: + skip_steps = max(skip_steps, step) num_steps = max(num_steps, step+1) if aimfile is not None: @@ -615,7 +616,8 @@ if aimfile is not None: constr_assumes[step].append((cexfile, smtexpr)) if not got_topt: - skip_steps = max(skip_steps, step) + if not check_witness: + skip_steps = max(skip_steps, step) # some solvers optimize the properties so that they fail one cycle early, # thus we check the properties in the cycle the aiger witness ends, and # if that doesn't work, we check the cycle after that as well. @@ -623,6 +625,11 @@ if aimfile is not None: step += 1 if inywfile is not None: + if not got_topt: + assume_skipped = 0 + skip_steps = 0 + num_steps = 0 + with open(inywfile, "r") as f: inyw = ReadWitness(f) @@ -717,6 +724,11 @@ if inywfile is not None: smt_constr = "(= %s #b%s)" % (smt_expr, bit_slice) constr_assumes[t].append((inywfile, smt_constr)) + if not got_topt: + if not check_witness: + skip_steps = max(skip_steps, t) + num_steps = max(num_steps, t+1) + if btorwitfile is not None: with open(btorwitfile, "r") as f: step = None -- cgit v1.2.3 From f7023d06a2bda56467c8f07cc44d3b92f0eab2ba Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 9 Aug 2022 15:43:26 +0200 Subject: sim: -hdlname option to preserve flattened hierarchy in sim output --- CHANGELOG | 2 ++ passes/sat/sim.cc | 50 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6403c5b9a..a1f4624ee 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,8 @@ Yosys 0.20 .. Yosys 0.20-dev - Added option "-formal" to "memory_map" pass - Added option "-witness" to "rename" - give public names to all signals present in yosys witness traces + - Added option "-hdlname" to "sim" pass - preserves hiearachy when writing + simulation output for a flattened design * Formal Verification - Added $anyinit cell to directly represent FFs with an unconstrained diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index ea64dce06..18a25a097 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -81,6 +81,7 @@ struct SimShared bool hide_internal = true; bool writeback = false; bool zinit = false; + bool hdlname = false; int rstlen = 1; FstData *fst = nullptr; double start_time = 0; @@ -738,9 +739,17 @@ struct SimInstance child.second->register_signals(id); } - void write_output_header(std::function enter_scope, std::function exit_scope, std::function register_signal) + void write_output_header(std::function enter_scope, std::function exit_scope, std::function register_signal) { - enter_scope(name()); + int exit_scopes = 1; + if (shared->hdlname && instance != nullptr && instance->name.isPublic() && instance->has_attribute(ID::hdlname)) { + auto hdlname = instance->get_hdlname_attribute(); + log_assert(!hdlname.empty()); + for (auto name : hdlname) + enter_scope("\\" + name); + exit_scopes = hdlname.size(); + } else + enter_scope(name()); dict registers; for (auto cell : module->cells()) @@ -756,13 +765,25 @@ struct SimInstance for (auto signal : signal_database) { - register_signal(signal.first, signal.second.first, registers.count(signal.first)!=0); + if (shared->hdlname && signal.first->name.isPublic() && signal.first->has_attribute(ID::hdlname)) { + auto hdlname = signal.first->get_hdlname_attribute(); + log_assert(!hdlname.empty()); + auto signal_name = std::move(hdlname.back()); + hdlname.pop_back(); + for (auto name : hdlname) + enter_scope("\\" + name); + register_signal(signal_name.c_str(), signal.first, signal.second.first, registers.count(signal.first)!=0); + for (auto name : hdlname) + exit_scope(); + } else + register_signal(log_id(signal.first->name), signal.first, signal.second.first, registers.count(signal.first)!=0); } for (auto child : children) child.second->write_output_header(enter_scope, exit_scope, register_signal); - exit_scope(); + for (int i = 0; i < exit_scopes; i++) + exit_scope(); } void register_output_step_values(std::map *data) @@ -1712,7 +1733,11 @@ struct VCDWriter : public OutputWriter worker->top->write_output_header( [this](IdString name) { vcdfile << stringf("$scope module %s $end\n", log_id(name)); }, [this]() { vcdfile << stringf("$upscope $end\n");}, - [this,use_signal](Wire *wire, int id, bool is_reg) { if (use_signal.at(id)) vcdfile << stringf("$var %s %d n%d %s%s $end\n", is_reg ? "reg" : "wire", GetSize(wire), id, wire->name[0] == '$' ? "\\" : "", log_id(wire)); } + [this,use_signal](const char *name, Wire *wire, int id, bool is_reg) { + if (use_signal.at(id)) { + vcdfile << stringf("$var %s %d n%d %s%s $end\n", is_reg ? "reg" : "wire", GetSize(wire), id, name[0] == '$' ? "\\" : "", name); + } + } ); vcdfile << stringf("$enddefinitions $end\n"); @@ -1770,11 +1795,10 @@ struct FSTWriter : public OutputWriter worker->top->write_output_header( [this](IdString name) { fstWriterSetScope(fstfile, FST_ST_VCD_MODULE, stringf("%s",log_id(name)).c_str(), nullptr); }, [this]() { fstWriterSetUpscope(fstfile); }, - [this,use_signal](Wire *wire, int id, bool is_reg) { + [this,use_signal](const char *name, Wire *wire, int id, bool is_reg) { if (!use_signal.at(id)) return; fstHandle fst_id = fstWriterCreateVar(fstfile, is_reg ? FST_VT_VCD_REG : FST_VT_VCD_WIRE, FST_VD_IMPLICIT, GetSize(wire), - stringf("%s%s", wire->name[0] == '$' ? "\\" : "", log_id(wire)).c_str(), 0); - + name, 0); mapping.emplace(id, fst_id); } ); @@ -1856,7 +1880,7 @@ struct AIWWriter : public OutputWriter worker->top->write_output_header( [](IdString) {}, []() {}, - [this](Wire *wire, int id, bool) { mapping[wire] = id; } + [this](const char */*name*/, Wire *wire, int id, bool) { mapping[wire] = id; } ); std::map current; @@ -1945,6 +1969,10 @@ struct SimPass : public Pass { log(" write the simulation results to an AIGER witness file\n"); log(" (requires a *.aim file via -map)\n"); log("\n"); + log(" -hdlname\n"); + log(" use the hdlname attribute when writing simulation results\n"); + log(" (preserves hierarchy in a flattened design)\n"); + log("\n"); log(" -x\n"); log(" ignore constant x outputs in simulation file.\n"); log("\n"); @@ -2057,6 +2085,10 @@ struct SimPass : public Pass { worker.outputfiles.emplace_back(std::unique_ptr(new AIWWriter(&worker, aiw_filename.c_str()))); continue; } + if (args[argidx] == "-hdlname") { + worker.hdlname = true; + continue; + } if (args[argidx] == "-n" && argidx+1 < args.size()) { numcycles = atoi(args[++argidx].c_str()); worker.cycles_set = true; -- cgit v1.2.3 From 1c36f4cc2cfe8832be19c9c6be5592c6ea55df19 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 17 Aug 2022 00:18:21 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4342882c3..4c6380619 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.20+22 +YOSYS_VER := 0.20+42 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3 From 5142fb3b5c6e7ed89fe74fcdff7775d6f09c34f5 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Thu, 18 Aug 2022 13:56:22 +0200 Subject: write_aiger: Fix non-$_FF_ FFs This broke while switching sby's formal flows to always use $_FF_'s. --- backends/aiger/aiger.cc | 2 +- tests/various/aiger_dff.ys | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 tests/various/aiger_dff.ys diff --git a/backends/aiger/aiger.cc b/backends/aiger/aiger.cc index 2ea999dc0..513f9d95a 100644 --- a/backends/aiger/aiger.cc +++ b/backends/aiger/aiger.cc @@ -202,7 +202,7 @@ struct AigerWriter ff_map[Q] = D; if (cell->type != ID($_FF_)) { - auto sig_clk = sigmap(cell->getPort(ID::CLK).as_bit()); + auto sig_clk = sigmap(cell->getPort(ID::C).as_bit()); ywmap_clocks[sig_clk] |= cell->type == ID($_DFF_N_) ? 2 : 1; } continue; diff --git a/tests/various/aiger_dff.ys b/tests/various/aiger_dff.ys new file mode 100644 index 000000000..057f3d774 --- /dev/null +++ b/tests/various/aiger_dff.ys @@ -0,0 +1,7 @@ +read_verilog -icells < Date: Fri, 19 Aug 2022 00:19:27 +0000 Subject: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4c6380619..d4573cd47 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.20+42 +YOSYS_VER := 0.20+45 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo -- cgit v1.2.3