diff --git a/.gitignore b/.gitignore index 47f758a9b..2367bccb3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ /Brewfile.lock.json ## build artifacts +/.git-abc-submodule-hash # compiler intermediate files *.o *.d diff --git a/Makefile b/Makefile index b744763c8..d17fe3a9a 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.58+35 +YOSYS_VER := 0.58+80 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) @@ -845,7 +845,17 @@ check-git-abc: exit 1; \ fi -abc/abc$(EXE) abc/libabc.a: | check-git-abc +.git-abc-submodule-hash: FORCE + @new=$$(cd abc 2>/dev/null && git rev-parse HEAD 2>/dev/null || echo none); \ + old=$$(cat .git-abc-submodule-hash 2>/dev/null || echo none); \ + if [ "$$new" != "$$old" ]; then \ + echo "$$new" > .git-abc-submodule-hash; \ + fi + +abc/abc$(EXE) abc/libabc.a: .git-abc-submodule-hash | check-git-abc + @if [ "$$(cd abc 2>/dev/null && git rev-parse HEAD 2>/dev/null)" != "$$(cat ../.git-abc-submodule-hash 2>/dev/null || echo none)" ]; then \ + rm -f abc/abc$(EXE); \ + fi $(P) $(Q) mkdir -p abc && $(MAKE) -C $(PROGRAM_PREFIX)abc -f "$(realpath $(YOSYS_SRC)/abc/Makefile)" ABCSRC="$(realpath $(YOSYS_SRC)/abc/)" $(S) $(ABCMKARGS) $(if $(filter %.a,$@),PROG="abc",PROG="abc$(EXE)") MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: " $(if $(filter %.a,$@),libabc.a) @@ -1121,7 +1131,7 @@ docs: docs/prep clean: clean-py rm -rf share - rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) $(PY_WRAP_INCLUDES) + rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) rm -f kernel/version_*.o kernel/version_*.cc rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d rm -rf tests/asicworld/*.out tests/asicworld/*.log @@ -1147,7 +1157,7 @@ clean-py: clean-abc: $(MAKE) -C abc DEP= clean - rm -f $(PROGRAM_PREFIX)yosys-abc$(EXE) $(PROGRAM_PREFIX)yosys-libabc.a abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a + rm -f $(PROGRAM_PREFIX)yosys-abc$(EXE) $(PROGRAM_PREFIX)yosys-libabc.a abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a .git-abc-submodule-hash mrproper: clean git clean -xdf diff --git a/abc b/abc index 8827bafb7..fa186342b 160000 --- a/abc +++ b/abc @@ -1 +1 @@ -Subproject commit 8827bafb7f288de6749dc6e30fa452f2040949c0 +Subproject commit fa186342baefea06e7c2aa13fe51f338ffc84912 diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index bba7249c7..ca7cf8a7f 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -98,6 +98,8 @@ struct BtorWorker vector ywmap_states; dict ywmap_clock_bits; dict ywmap_clock_inputs; + vector ywmap_asserts; + vector ywmap_assumes; PrettyJson ywmap_json; @@ -1280,6 +1282,8 @@ struct BtorWorker btorf("%d or %d %d %d\n", nid_a_or_not_en, sid, nid_a, nid_not_en); btorf("%d constraint %d\n", nid, nid_a_or_not_en); + if (ywmap_json.active()) ywmap_assumes.emplace_back(cell); + btorf_pop(log_id(cell)); } @@ -1304,6 +1308,8 @@ struct BtorWorker } else { int nid = next_nid++; btorf("%d bad %d%s\n", nid, nid_en_and_not_a, getinfo(cell, true)); + + if (ywmap_json.active()) ywmap_asserts.emplace_back(cell); } } @@ -1461,6 +1467,7 @@ struct BtorWorker log_assert(cursor == 0); log_assert(GetSize(todo) == 1); btorf("%d bad %d\n", nid, todo[cursor]); + // What do we do with ywmap_asserts when using single_bad? } } @@ -1526,6 +1533,18 @@ struct BtorWorker emit_ywmap_btor_sig(entry); ywmap_json.end_array(); + ywmap_json.name("asserts"); + ywmap_json.begin_array(); + for (Cell *cell : ywmap_asserts) + ywmap_json.value(witness_path(cell)); + ywmap_json.end_array(); + + ywmap_json.name("assumes"); + ywmap_json.begin_array(); + for (Cell *cell : ywmap_assumes) + ywmap_json.value(witness_path(cell)); + ywmap_json.end_array(); + ywmap_json.end_object(); } } diff --git a/frontends/rtlil/rtlil_frontend.cc b/frontends/rtlil/rtlil_frontend.cc index b54cd8f14..04d01fc93 100644 --- a/frontends/rtlil/rtlil_frontend.cc +++ b/frontends/rtlil/rtlil_frontend.cc @@ -324,29 +324,27 @@ struct RTLILFrontendWorker { RTLIL::SigSpec parse_sigspec() { + RTLIL::SigSpec sig; + if (try_parse_char('{')) { std::vector parts; while (!try_parse_char('}')) parts.push_back(parse_sigspec()); - RTLIL::SigSpec sig; for (auto it = parts.rbegin(); it != parts.rend(); ++it) sig.append(std::move(*it)); - return sig; - } - - RTLIL::SigSpec sig; - - // We could add a special path for parsing IdStrings that must already exist, - // as here. - // We don't need to addref/release in this case. - std::optional id = try_parse_id(); - if (id.has_value()) { - RTLIL::Wire *wire = current_module->wire(*id); - if (wire == nullptr) - error("Wire `%s' not found.", *id); - sig = RTLIL::SigSpec(wire); } else { - sig = RTLIL::SigSpec(parse_const()); + // We could add a special path for parsing IdStrings that must already exist, + // as here. + // We don't need to addref/release in this case. + std::optional id = try_parse_id(); + if (id.has_value()) { + RTLIL::Wire *wire = current_module->wire(*id); + if (wire == nullptr) + error("Wire `%s' not found.", *id); + sig = RTLIL::SigSpec(wire); + } else { + sig = RTLIL::SigSpec(parse_const()); + } } while (try_parse_char('[')) { diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 408542131..ff8932dac 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -168,12 +168,12 @@ string get_full_netlist_name(Netlist *nl) std::string format_src_location(DesignObj *obj) { - if (obj == nullptr || obj->Linefile() == nullptr) + if (obj == nullptr || !obj->Linefile()) return std::string(); #ifdef VERIFIC_LINEFILE_INCLUDES_COLUMNS - return stringf("%s:%d.%d-%d.%d", LineFile::GetFileName(obj->Linefile()), obj->Linefile()->GetLeftLine(), obj->Linefile()->GetLeftCol(), obj->Linefile()->GetRightLine(), obj->Linefile()->GetRightCol()); + return stringf("%s:%d.%d-%d.%d", LineFile::GetFileName(obj->Linefile()), obj->Linefile()->GetLeftLine(), obj->Linefile()->GetLeftCol(), obj->Linefile()->GetRightLine(), obj->Linefile()->GetRightCol()); #else - return stringf("%s:%d", LineFile::GetFileName(obj->Linefile()), LineFile::GetLineNo(obj->Linefile())); + return stringf("%s:%d", LineFile::GetFileName(obj->Linefile()), LineFile::GetLineNo(obj->Linefile())); #endif } @@ -1663,7 +1663,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma if (*ascii_initdata == 0) break; if (*ascii_initdata == '0' || *ascii_initdata == '1') { - initval.bits()[bit_idx] = (*ascii_initdata == '0') ? State::S0 : State::S1; + initval.set(bit_idx, (*ascii_initdata == '0') ? State::S0 : State::S1); initval_valid = true; } ascii_initdata++; @@ -1787,9 +1787,9 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma if (init_nets.count(net)) { if (init_nets.at(net) == '0') - initval.bits().at(bitidx) = State::S0; + initval.set(bitidx, State::S0); if (init_nets.at(net) == '1') - initval.bits().at(bitidx) = State::S1; + initval.set(bitidx, State::S1); initval_valid = true; init_nets.erase(net); } @@ -1862,13 +1862,13 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma if (bit.wire->attributes.count(ID::init)) initval = bit.wire->attributes.at(ID::init); - while (GetSize(initval) < GetSize(bit.wire)) - initval.bits().push_back(State::Sx); + if (GetSize(initval) < GetSize(bit.wire)) + initval.resize(GetSize(bit.wire), State::Sx); if (it.second == '0') - initval.bits().at(bit.offset) = State::S0; + initval.set(bit.offset, State::S0); if (it.second == '1') - initval.bits().at(bit.offset) = State::S1; + initval.set(bit.offset, State::S1); bit.wire->attributes[ID::init] = initval; } @@ -1995,7 +1995,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma if (import_netlist_instance_cells(inst, inst_name)) continue; if (inst->IsOperator() && !verific_sva_prims.count(inst->Type())) - log_warning("Unsupported Verific operator: %s (fallback to gate level implementation provided by verific)\n", inst->View()->Owner()->Name()); + log_warning("%sUnsupported Verific operator: %s (fallback to gate level implementation provided by verific)\n", announce_src_location(inst), inst->View()->Owner()->Name()); } else { if (import_netlist_instance_gates(inst, inst_name)) continue; @@ -2055,7 +2055,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma } Const qx_init = Const(State::S1, width); - qx_init.bits().resize(2 * width, State::S0); + qx_init.resize(2 * width, State::S0); clocking.addDff(new_verific_id(inst), sig_dx, sig_qx, qx_init); module->addXnor(new_verific_id(inst), sig_dx, sig_qx, sig_ox); @@ -2320,7 +2320,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma continue; if (non_ff_bits.count(SigBit(wire, i))) - initval.bits()[i] = State::Sx; + initval.set(i, State::Sx); } if (wire->port_input) { @@ -2513,7 +2513,7 @@ Cell *VerificClocking::addDff(IdString name, SigSpec sig_d, SigSpec sig_q, Const if (c.wire && c.wire->attributes.count(ID::init)) { Const val = c.wire->attributes.at(ID::init); for (int i = 0; i < GetSize(c); i++) - initval.bits()[offset+i] = val[c.offset+i]; + initval.set(offset+i, val[c.offset+i]); } offset += GetSize(c); } @@ -2584,7 +2584,7 @@ Cell *VerificClocking::addAldff(IdString name, RTLIL::SigSpec sig_aload, RTLIL:: if (c.wire && c.wire->attributes.count(ID::init)) { Const val = c.wire->attributes.at(ID::init); for (int i = 0; i < GetSize(c); i++) - initval.bits()[offset+i] = val[c.offset+i]; + initval.set(offset+i, val[c.offset+i]); } offset += GetSize(c); } diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc index 50e0049ae..dffe6e8e0 100644 --- a/frontends/verific/verificsva.cc +++ b/frontends/verific/verificsva.cc @@ -577,7 +577,7 @@ struct SvaFsm if (delta_pos >= 0 && i_within_j && j_within_i) { did_something = true; - values[i].bits()[delta_pos] = State::Sa; + values[i].set(delta_pos, State::Sa); values[j] = values.back(); values.pop_back(); goto next_pair; diff --git a/kernel/io.cc b/kernel/io.cc index 4c593501c..9e9eb9fb0 100644 --- a/kernel/io.cc +++ b/kernel/io.cc @@ -384,6 +384,13 @@ std::string escape_filename_spaces(const std::string& filename) return out; } +void append_globbed(std::vector& paths, std::string pattern) +{ + rewrite_filename(pattern); + std::vector globbed = glob_filename(pattern); + copy(globbed.begin(), globbed.end(), back_inserter(paths)); +} + void format_emit_unescaped(std::string &result, std::string_view fmt) { result.reserve(result.size() + fmt.size()); diff --git a/kernel/io.h b/kernel/io.h index 2ad0a6466..b3922bef0 100644 --- a/kernel/io.h +++ b/kernel/io.h @@ -469,6 +469,7 @@ bool is_absolute_path(std::string filename); void remove_directory(std::string dirname); bool create_directory(const std::string& dirname); std::string escape_filename_spaces(const std::string& filename); +void append_globbed(std::vector& paths, std::string pattern); YOSYS_NAMESPACE_END diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc index 9bf615a7e..2dbeadac2 100644 --- a/passes/cmds/Makefile.inc +++ b/passes/cmds/Makefile.inc @@ -57,3 +57,4 @@ OBJS += passes/cmds/abstract.o OBJS += passes/cmds/test_select.o OBJS += passes/cmds/timeest.o OBJS += passes/cmds/linecoverage.o +OBJS += passes/cmds/sort.o diff --git a/passes/cmds/box_derive.cc b/passes/cmds/box_derive.cc index a0faacc9a..2590baa93 100644 --- a/passes/cmds/box_derive.cc +++ b/passes/cmds/box_derive.cc @@ -51,6 +51,9 @@ struct BoxDerivePass : Pass { log(" replaces the internal Yosys naming scheme in which the names of derived\n"); log(" modules start with '$paramod$')\n"); log("\n"); + log(" -apply_derived_type\n"); + log(" use the derived modules\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *d) override { @@ -59,11 +62,14 @@ struct BoxDerivePass : Pass { size_t argidx; IdString naming_attr; IdString base_name; + bool apply_mode = false; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-naming_attr" && argidx + 1 < args.size()) naming_attr = RTLIL::escape_id(args[++argidx]); else if (args[argidx] == "-base" && argidx + 1 < args.size()) base_name = RTLIL::escape_id(args[++argidx]); + else if (args[argidx] == "-apply_derived_type") + apply_mode = true; else break; } @@ -90,24 +96,29 @@ struct BoxDerivePass : Pass { auto index = std::make_pair(base->name, cell->parameters); - if (cell->parameters.empty() || done.count(index)) + if (cell->parameters.empty()) continue; - IdString derived_type = base->derive(d, cell->parameters); - Module *derived = d->module(derived_type); - log_assert(derived && "Failed to derive module\n"); - log_debug("derived %s\n", derived_type); + if (!done.count(index)) { + IdString derived_type = base->derive(d, cell->parameters); + Module *derived = d->module(derived_type); + log_assert(derived && "Failed to derive module\n"); + log("derived %s\n", derived_type); - if (!naming_attr.empty() && derived->has_attribute(naming_attr)) { - IdString new_name = RTLIL::escape_id(derived->get_string_attribute(naming_attr)); - if (!new_name.isPublic()) - log_error("Derived module %s cannot be renamed to private name %s.\n", - log_id(derived), log_id(new_name)); - derived->attributes.erase(naming_attr); - d->rename(derived, new_name); + if (!naming_attr.empty() && derived->has_attribute(naming_attr)) { + IdString new_name = RTLIL::escape_id(derived->get_string_attribute(naming_attr)); + if (!new_name.isPublic()) + log_error("Derived module %s cannot be renamed to private name %s.\n", + log_id(derived), log_id(new_name)); + derived->attributes.erase(naming_attr); + d->rename(derived, new_name); + } + + done[index] = derived; } - done[index] = derived; + if (apply_mode) + cell->type = done[index]->name; } } } diff --git a/passes/cmds/chtype.cc b/passes/cmds/chtype.cc index 6f9ca9a45..eb194f3e3 100644 --- a/passes/cmds/chtype.cc +++ b/passes/cmds/chtype.cc @@ -22,6 +22,27 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +static void publish(RTLIL::IdString& id) { + if (id.begins_with("$")) { + log_debug("publishing %s\n", id.c_str()); + id = "\\" + id.str(); + log_debug("published %s\n", id.c_str()); + } +} + +static void publish_design(RTLIL::Design* design) { + auto saved_modules = design->modules_; + design->modules_.clear(); + for (auto& [name, mod] : saved_modules) { + publish(mod->name); + design->modules_[mod->name] = mod; + for (auto* cell : mod->cells()) { + publish(cell->type); + } + } +} + + struct ChtypePass : public Pass { ChtypePass() : Pass("chtype", "change type of cells in the design") { } void help() override @@ -38,12 +59,16 @@ struct ChtypePass : public Pass { log(" -map \n"); log(" change cells types that match to \n"); log("\n"); + log(" -publish_icells\n"); + log(" change internal cells types to public types\n"); + log("\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { IdString set_type; dict map_types; + bool publish_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -58,10 +83,17 @@ struct ChtypePass : public Pass { map_types[old_type] = new_type; continue; } + if (args[argidx] == "-publish_icells") { + publish_mode = true; + continue; + } break; } extra_args(args, argidx, design); + if (publish_mode) + publish_design(design); + for (auto module : design->selected_modules()) { for (auto cell : module->selected_cells()) diff --git a/passes/cmds/plugin.cc b/passes/cmds/plugin.cc index 191261a17..dec53cf37 100644 --- a/passes/cmds/plugin.cc +++ b/passes/cmds/plugin.cc @@ -22,6 +22,8 @@ #ifdef YOSYS_ENABLE_PLUGINS # include +# include +namespace fs = std::filesystem; #endif #ifdef YOSYS_ENABLE_PYTHON @@ -39,6 +41,26 @@ std::map loaded_python_plugins; std::map loaded_plugin_aliases; #ifdef YOSYS_ENABLE_PLUGINS + +static constexpr const char *path_delimiters = fs::path::preferred_separator == '\\' ? ";" : ":" ; + +inline const std::vector get_plugin_search_paths() { + std::vector result; + const char *yosys_plugin_path = std::getenv("YOSYS_PLUGIN_PATH"); + if (yosys_plugin_path != nullptr && strlen(yosys_plugin_path)) { + // make mutable. std::string also manages allocation as a bonus + // guaranteed contiguous in c++>=11 + std::string copy{yosys_plugin_path}; + char *token = nullptr; + char *rest = ©[0]; + while ((token = strtok_r(rest, path_delimiters, &rest))) { + result.push_back(fs::path(token)); + } + } + result.push_back(fs::path(proc_share_dirname()) / "plugins"); // lowest priority + return result; +} + void load_plugin(std::string filename, std::vector aliases) { std::string orig_filename = filename; @@ -55,17 +77,17 @@ void load_plugin(std::string filename, std::vector aliases) const bool is_loaded = loaded_plugins.count(orig_filename); #endif + fs::path full_path = fs::absolute(filename); + if (!is_loaded) { // Check if we're loading a python script - if (filename.rfind(".py") != std::string::npos) { + if (full_path.extension() == ".py") { #ifdef YOSYS_ENABLE_PYTHON - py::object Path = py::module_::import("pathlib").attr("Path"); - py::object full_path = Path(py::cast(filename)); - py::object plugin_python_path = full_path.attr("parent"); - auto basename = py::cast(full_path.attr("stem")); + fs::path plugin_python_path = full_path.parent_path(); + fs::path basename = full_path.stem(); py::object sys = py::module_::import("sys"); - sys.attr("path").attr("insert")(0, py::str(plugin_python_path)); + sys.attr("path").attr("insert")(0, py::str(plugin_python_path.c_str())); try { auto module_container = py::module_::import(basename.c_str()); @@ -83,23 +105,25 @@ void load_plugin(std::string filename, std::vector aliases) #endif } else { // Otherwise we assume it's a native plugin - void *hdl = dlopen(filename.c_str(), RTLD_LAZY|RTLD_LOCAL); - // We were unable to open the file, try to do so from the plugin directory - if (hdl == NULL && orig_filename.find('/') == std::string::npos) { - hdl = dlopen([orig_filename]() { - std::string new_path = proc_share_dirname() + "plugins/" + orig_filename; - - // Check if we need to append .so - if (new_path.find(".so") == std::string::npos) - new_path.append(".so"); - - return new_path; - }().c_str(), RTLD_LAZY|RTLD_LOCAL); + // We were unable to open the file, try to do so from plugin search + // paths + if (hdl == nullptr && orig_filename.find('/') == std::string::npos) { + const std::vector search_paths = get_plugin_search_paths(); + for (const auto &search_path: search_paths) { + fs::path potential_path = search_path / orig_filename; + if (potential_path.extension() != ".so") { + potential_path = search_path / (orig_filename + ".so"); + } + hdl = dlopen(potential_path.string().c_str(), RTLD_LAZY | RTLD_LOCAL); + if (hdl != nullptr) { + break; + } + } } - if (hdl == NULL) + if (hdl == nullptr) log_cmd_error("Can't load module `%s': %s\n", filename, dlerror()); loaded_plugins[orig_filename] = hdl; @@ -116,7 +140,7 @@ void load_plugin(std::string, std::vector) log_error( "\n This version of Yosys cannot load plugins at runtime.\n" " Some plugins may have been included at build time.\n" - " Use option `-H' to see the available built-in and plugin commands.\n" + " Use `yosys -H' to see the available built-in and plugin commands.\n" ); } #endif diff --git a/passes/cmds/sort.cc b/passes/cmds/sort.cc new file mode 100644 index 000000000..ab058880e --- /dev/null +++ b/passes/cmds/sort.cc @@ -0,0 +1,26 @@ +#include "kernel/yosys.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct SortPass : Pass { + SortPass() : Pass("sort", "sort the design objects") {} + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" sort\n"); + log("\n"); + log("Sorts the design objects.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *d) override + { + log_header(d, "Executing SORT pass.\n"); + if (args.size() != 1) + log_cmd_error("This pass takes no arguments.\n"); + d->sort(); + } +} SortPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index fac7bd744..a29651653 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -1392,7 +1392,7 @@ struct SimWorker : SimShared } } - void run(Module *topmod, int numcycles) + void run(Module *topmod, int cycle_width, int numcycles) { log_assert(top == nullptr); top = new SimInstance(this, scope, topmod); @@ -1418,20 +1418,20 @@ struct SimWorker : SimShared for (int cycle = 0; cycle < numcycles; cycle++) { if (debug) - log("\n===== %d =====\n", 10*cycle + 5); + log("\n===== %d =====\n", int(cycle_width*cycle + cycle_width/2)); else if (verbose) log("Simulating cycle %d.\n", (cycle*2)+1); set_inports(clock, State::S0); set_inports(clockn, State::S1); update(true); - register_output_step(10*cycle + 5); + register_output_step(cycle_width*cycle + cycle_width/2); if (cycle == 0) top->set_initstate_outputs(State::S0); if (debug) - log("\n===== %d =====\n", 10*cycle + 10); + log("\n===== %d =====\n", int(cycle_width*cycle + cycle_width)); else if (verbose) log("Simulating cycle %d.\n", (cycle*2)+2); @@ -1444,10 +1444,10 @@ struct SimWorker : SimShared } update(true); - register_output_step(10*cycle + 10); + register_output_step(cycle_width*cycle + cycle_width); } - register_output_step(10*numcycles + 2); + register_output_step(cycle_width*numcycles + 2); write_output_files(); } @@ -1582,7 +1582,7 @@ struct SimWorker : SimShared return atoi(name.substr(pos+1).c_str()); } - void run_cosim_aiger_witness(Module *topmod) + void run_cosim_aiger_witness(Module *topmod, int cycle_width) { log_assert(top == nullptr); if (!multiclock && (clock.size()+clockn.size())==0) @@ -1691,18 +1691,18 @@ struct SimWorker : SimShared set_inports(clockn, State::S1); } update(true); - register_output_step(10*cycle); + register_output_step(cycle_width*cycle); if (!multiclock && cycle) { set_inports(clock, State::S0); set_inports(clockn, State::S1); update(true); - register_output_step(10*cycle + 5); + register_output_step(cycle_width*cycle + cycle_width/2); } cycle++; break; } } - register_output_step(10*cycle); + register_output_step(cycle_width*cycle); write_output_files(); } @@ -1730,7 +1730,7 @@ struct SimWorker : SimShared return name.substr(0, pos); } - void run_cosim_btor2_witness(Module *topmod) + void run_cosim_btor2_witness(Module *topmod, int cycle_width) { log_assert(top == nullptr); if (!multiclock && (clock.size()+clockn.size())==0) @@ -1768,12 +1768,12 @@ struct SimWorker : SimShared set_inports(clock, State::S1); set_inports(clockn, State::S0); update(true); - register_output_step(10*cycle+0); + register_output_step(cycle_width*cycle + 0); if (!multiclock) { set_inports(clock, State::S0); set_inports(clockn, State::S1); update(true); - register_output_step(10*cycle+5); + register_output_step(cycle_width*cycle + cycle_width/2); } cycle++; prev_cycle = curr_cycle; @@ -1832,7 +1832,7 @@ struct SimWorker : SimShared break; } } - register_output_step(10*cycle); + register_output_step(cycle_width*cycle); write_output_files(); } @@ -1983,7 +1983,7 @@ struct SimWorker : SimShared } } - void run_cosim_yw_witness(Module *topmod, int append) + void run_cosim_yw_witness(Module *topmod, int cycle_width, int append) { if (!clock.empty()) log_cmd_error("The -clock option is not required nor supported when reading a Yosys witness file.\n"); @@ -2013,7 +2013,7 @@ struct SimWorker : SimShared log("Simulating non-active clock edge.\n"); set_yw_clocks(yw, hierarchy, false); update(false); - register_output_step(5); + register_output_step(cycle_width/2); } top->set_initstate_outputs(State::S0); } @@ -2026,18 +2026,18 @@ struct SimWorker : SimShared set_yw_state(yw, hierarchy, cycle); set_yw_clocks(yw, hierarchy, true); update(true); - register_output_step(10 * cycle); + register_output_step(cycle_width*cycle); if (!yw.clocks.empty()) { if (debug) log("Simulating non-active clock edge.\n"); set_yw_clocks(yw, hierarchy, false); update(false); - register_output_step(5 + 10 * cycle); + register_output_step(cycle_width*cycle + cycle_width/2); } } - register_output_step(10 * (GetSize(yw.steps) + append)); + register_output_step(cycle_width * (GetSize(yw.steps) + append)); write_output_files(); } @@ -2630,6 +2630,9 @@ struct SimPass : public Pass { log(" File formats supported: FST, VCD, AIW, WIT and .yw\n"); log(" VCD support requires vcd2fst external tool to be present\n"); log("\n"); + log(" -width \n"); + log(" cycle width in generated simulation output (must be divisible by 2).\n"); + log("\n"); log(" -append \n"); log(" number of extra clock cycles to simulate for a Yosys witness input\n"); log("\n"); @@ -2689,6 +2692,7 @@ struct SimPass : public Pass { { SimWorker worker; int numcycles = 20; + int cycle_width = 10; int append = 0; bool start_set = false, stop_set = false, at_set = false; @@ -2781,6 +2785,12 @@ struct SimPass : public Pass { append = atoi(args[++argidx].c_str()); continue; } + if (args[argidx] == "-width" && argidx+1 < args.size()) { + cycle_width = atoi(args[++argidx].c_str()); + if (cycle_width <= 0 || (cycle_width % 2)) + log_cmd_error("Cycle width must be positive even number.\n"); + continue; + } if (args[argidx] == "-map" && argidx+1 < args.size()) { std::string map_filename = args[++argidx]; rewrite_filename(map_filename); @@ -2872,7 +2882,7 @@ struct SimPass : public Pass { } if (worker.sim_filename.empty()) - worker.run(top_mod, numcycles); + worker.run(top_mod, cycle_width, numcycles); else { std::string filename_trim = file_base_name(worker.sim_filename); if (filename_trim.size() > 4 && ((filename_trim.compare(filename_trim.size()-4, std::string::npos, ".fst") == 0) || @@ -2881,11 +2891,11 @@ struct SimPass : public Pass { } else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".aiw") == 0) { if (worker.map_filename.empty()) log_cmd_error("For AIGER witness file map parameter is mandatory.\n"); - worker.run_cosim_aiger_witness(top_mod); + worker.run_cosim_aiger_witness(top_mod, cycle_width); } else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".wit") == 0) { - worker.run_cosim_btor2_witness(top_mod); + worker.run_cosim_btor2_witness(top_mod, cycle_width); } else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".yw") == 0) { - worker.run_cosim_yw_witness(top_mod, append); + worker.run_cosim_yw_witness(top_mod, cycle_width, append); } else { log_cmd_error("Unhandled extension for simulation input file `%s`.\n", worker.sim_filename); } diff --git a/passes/techmap/clockgate.cc b/passes/techmap/clockgate.cc index 7c6ca5551..b68e5d93d 100644 --- a/passes/techmap/clockgate.cc +++ b/passes/techmap/clockgate.cc @@ -290,9 +290,7 @@ struct ClockgatePass : public Pass { continue; } if (args[argidx] == "-liberty" && argidx+1 < args.size()) { - std::string liberty_file = args[++argidx]; - rewrite_filename(liberty_file); - liberty_files.push_back(liberty_file); + append_globbed(liberty_files, args[++argidx]); continue; } if (args[argidx] == "-dont_use" && argidx+1 < args.size()) { diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index f3b96aeec..f2bd16082 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -609,9 +609,7 @@ struct DfflibmapPass : public Pass { { std::string arg = args[argidx]; if (arg == "-liberty" && argidx+1 < args.size()) { - std::string liberty_file = args[++argidx]; - rewrite_filename(liberty_file); - liberty_files.push_back(liberty_file); + append_globbed(liberty_files, args[++argidx]); continue; } if (arg == "-prepare") { diff --git a/passes/techmap/libcache.cc b/passes/techmap/libcache.cc index c833a6046..e4326c49f 100644 --- a/passes/techmap/libcache.cc +++ b/passes/techmap/libcache.cc @@ -96,9 +96,7 @@ quiet = true; continue; } - std::string fname = args[argidx]; - rewrite_filename(fname); - paths.push_back(fname); + append_globbed(paths, args[argidx]); break; } int modes = enable + disable + purge + list + verbose + quiet; diff --git a/techlibs/gowin/Makefile.inc b/techlibs/gowin/Makefile.inc index 9ec7dce4d..df1b79317 100644 --- a/techlibs/gowin/Makefile.inc +++ b/techlibs/gowin/Makefile.inc @@ -8,6 +8,7 @@ $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_xtra_gw2a.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_xtra_gw5a.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/arith_map.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map.v)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map_gw5a.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/brams.txt)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams_map.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams.txt)) diff --git a/techlibs/gowin/brams_map_gw5a.v b/techlibs/gowin/brams_map_gw5a.v new file mode 100644 index 000000000..246146ee5 --- /dev/null +++ b/techlibs/gowin/brams_map_gw5a.v @@ -0,0 +1,399 @@ +`define DEF_FUNCS \ + function [255:0] init_slice_x8; \ + input integer idx; \ + integer i; \ + for (i = 0; i < 32; i = i + 1) begin \ + init_slice_x8[i*8+:8] = INIT[(idx * 32 + i) * 9+:8]; \ + end \ + endfunction \ + function [287:0] init_slice_x9; \ + input integer idx; \ + init_slice_x9 = INIT[idx * 288+:288]; \ + endfunction \ + +`define x8_width(width) (width / 9 * 8 + width % 9) +`define x8_rd_data(data) {1'bx, data[31:24], 1'bx, data[23:16], 1'bx, data[15:8], 1'bx, data[7:0]} +`define x8_wr_data(data) {data[34:27], data[25:18], data[16:9], data[7:0]} +`define addrbe_always(width, addr) (width < 18 ? addr : width == 18 ? {addr[13:4], 4'b0011} : {addr[13:5], 5'b01111}) + + +`define INIT(func) \ + .INIT_RAM_00(func('h00)), \ + .INIT_RAM_01(func('h01)), \ + .INIT_RAM_02(func('h02)), \ + .INIT_RAM_03(func('h03)), \ + .INIT_RAM_04(func('h04)), \ + .INIT_RAM_05(func('h05)), \ + .INIT_RAM_06(func('h06)), \ + .INIT_RAM_07(func('h07)), \ + .INIT_RAM_08(func('h08)), \ + .INIT_RAM_09(func('h09)), \ + .INIT_RAM_0A(func('h0a)), \ + .INIT_RAM_0B(func('h0b)), \ + .INIT_RAM_0C(func('h0c)), \ + .INIT_RAM_0D(func('h0d)), \ + .INIT_RAM_0E(func('h0e)), \ + .INIT_RAM_0F(func('h0f)), \ + .INIT_RAM_10(func('h10)), \ + .INIT_RAM_11(func('h11)), \ + .INIT_RAM_12(func('h12)), \ + .INIT_RAM_13(func('h13)), \ + .INIT_RAM_14(func('h14)), \ + .INIT_RAM_15(func('h15)), \ + .INIT_RAM_16(func('h16)), \ + .INIT_RAM_17(func('h17)), \ + .INIT_RAM_18(func('h18)), \ + .INIT_RAM_19(func('h19)), \ + .INIT_RAM_1A(func('h1a)), \ + .INIT_RAM_1B(func('h1b)), \ + .INIT_RAM_1C(func('h1c)), \ + .INIT_RAM_1D(func('h1d)), \ + .INIT_RAM_1E(func('h1e)), \ + .INIT_RAM_1F(func('h1f)), \ + .INIT_RAM_20(func('h20)), \ + .INIT_RAM_21(func('h21)), \ + .INIT_RAM_22(func('h22)), \ + .INIT_RAM_23(func('h23)), \ + .INIT_RAM_24(func('h24)), \ + .INIT_RAM_25(func('h25)), \ + .INIT_RAM_26(func('h26)), \ + .INIT_RAM_27(func('h27)), \ + .INIT_RAM_28(func('h28)), \ + .INIT_RAM_29(func('h29)), \ + .INIT_RAM_2A(func('h2a)), \ + .INIT_RAM_2B(func('h2b)), \ + .INIT_RAM_2C(func('h2c)), \ + .INIT_RAM_2D(func('h2d)), \ + .INIT_RAM_2E(func('h2e)), \ + .INIT_RAM_2F(func('h2f)), \ + .INIT_RAM_30(func('h30)), \ + .INIT_RAM_31(func('h31)), \ + .INIT_RAM_32(func('h32)), \ + .INIT_RAM_33(func('h33)), \ + .INIT_RAM_34(func('h34)), \ + .INIT_RAM_35(func('h35)), \ + .INIT_RAM_36(func('h36)), \ + .INIT_RAM_37(func('h37)), \ + .INIT_RAM_38(func('h38)), \ + .INIT_RAM_39(func('h39)), \ + .INIT_RAM_3A(func('h3a)), \ + .INIT_RAM_3B(func('h3b)), \ + .INIT_RAM_3C(func('h3c)), \ + .INIT_RAM_3D(func('h3d)), \ + .INIT_RAM_3E(func('h3e)), \ + .INIT_RAM_3F(func('h3f)), + +module $__GOWIN_SP_ (...); + +parameter INIT = 0; +parameter OPTION_RESET_MODE = "SYNC"; + +parameter PORT_A_WIDTH = 36; +parameter PORT_A_OPTION_WRITE_MODE = 0; + +input PORT_A_CLK; +input PORT_A_CLK_EN; +input PORT_A_WR_EN; +input PORT_A_RD_SRST; +input PORT_A_RD_ARST; +input [13:0] PORT_A_ADDR; +input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA; +output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA; + +`DEF_FUNCS + +wire RST = OPTION_RESET_MODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST; +wire [13:0] AD = `addrbe_always(PORT_A_WIDTH, PORT_A_ADDR); + +generate + +if (PORT_A_WIDTH < 9) begin + + wire [31:0] DI = `x8_wr_data(PORT_A_WR_DATA); + wire [31:0] DO; + + assign PORT_A_RD_DATA = `x8_rd_data(DO); + + SP #( + `INIT(init_slice_x8) + .READ_MODE(1'b0), + .WRITE_MODE(PORT_A_OPTION_WRITE_MODE), + .BIT_WIDTH(`x8_width(PORT_A_WIDTH)), + .BLK_SEL(3'b000), + .RESET_MODE(OPTION_RESET_MODE), + ) _TECHMAP_REPLACE_ ( + .BLKSEL(3'b000), + .CLK(PORT_A_CLK), + .CE(PORT_A_CLK_EN), + .WRE(PORT_A_WR_EN), + .RESET(RST), + .OCE(1'b1), + .AD(AD), + .DI(DI), + .DO(DO), + ); + +end else begin + + wire [35:0] DI = PORT_A_WR_DATA; + wire [35:0] DO; + + assign PORT_A_RD_DATA = DO; + + SPX9 #( + `INIT(init_slice_x9) + .READ_MODE(1'b0), + .WRITE_MODE(PORT_A_OPTION_WRITE_MODE), + .BIT_WIDTH(PORT_A_WIDTH), + .BLK_SEL(3'b000), + .RESET_MODE(OPTION_RESET_MODE), + ) _TECHMAP_REPLACE_ ( + .BLKSEL(3'b000), + .CLK(PORT_A_CLK), + .CE(PORT_A_CLK_EN), + .WRE(PORT_A_WR_EN), + .RESET(RST), + .OCE(1'b1), + .AD(AD), + .DI(DI), + .DO(DO), + ); + +end + +endgenerate + +endmodule + + +module $__GOWIN_DP_ (...); + +parameter INIT = 0; +parameter OPTION_RESET_MODE = "SYNC"; + +parameter PORT_A_WIDTH = 18; +parameter PORT_A_OPTION_WRITE_MODE = 0; + +parameter PORT_B_WIDTH = 18; +parameter PORT_B_OPTION_WRITE_MODE = 0; + +input PORT_A_CLK; +input PORT_A_CLK_EN; +input PORT_A_WR_EN; +input PORT_A_RD_SRST; +input PORT_A_RD_ARST; +input [13:0] PORT_A_ADDR; +input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA; +output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA; + +input PORT_B_CLK; +input PORT_B_CLK_EN; +input PORT_B_WR_EN; +input PORT_B_RD_SRST; +input PORT_B_RD_ARST; +input [13:0] PORT_B_ADDR; +input [PORT_A_WIDTH-1:0] PORT_B_WR_DATA; +output [PORT_A_WIDTH-1:0] PORT_B_RD_DATA; + +`DEF_FUNCS + +wire RSTA = OPTION_RESET_MODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST; +wire RSTB = OPTION_RESET_MODE == "SYNC" ? PORT_B_RD_SRST : PORT_B_RD_ARST; +wire [13:0] ADA = `addrbe_always(PORT_A_WIDTH, PORT_A_ADDR); +wire [13:0] ADB = `addrbe_always(PORT_B_WIDTH, PORT_B_ADDR); + +generate + +if (PORT_A_WIDTH < 9 || PORT_B_WIDTH < 9) begin + + wire [15:0] DIA = `x8_wr_data(PORT_A_WR_DATA); + wire [15:0] DIB = `x8_wr_data(PORT_B_WR_DATA); + wire [15:0] DOA; + wire [15:0] DOB; + + assign PORT_A_RD_DATA = `x8_rd_data(DOA); + assign PORT_B_RD_DATA = `x8_rd_data(DOB); + + DPB #( + `INIT(init_slice_x8) + .READ_MODE0(1'b0), + .READ_MODE1(1'b0), + .WRITE_MODE0(PORT_A_OPTION_WRITE_MODE), + .WRITE_MODE1(PORT_B_OPTION_WRITE_MODE), + .BIT_WIDTH_0(`x8_width(PORT_A_WIDTH)), + .BIT_WIDTH_1(`x8_width(PORT_B_WIDTH)), + .BLK_SEL_0(3'b000), + .BLK_SEL_1(3'b000), + .RESET_MODE(OPTION_RESET_MODE), + ) _TECHMAP_REPLACE_ ( + .BLKSELA(3'b000), + .BLKSELB(3'b000), + + .CLKA(PORT_A_CLK), + .CEA(PORT_A_CLK_EN), + .WREA(PORT_A_WR_EN), + .RESETA(RSTA), + .OCEA(1'b1), + .ADA(ADA), + .DIA(DIA), + .DOA(DOA), + + .CLKB(PORT_B_CLK), + .CEB(PORT_B_CLK_EN), + .WREB(PORT_B_WR_EN), + .RESETB(RSTB), + .OCEB(1'b1), + .ADB(ADB), + .DIB(DIB), + .DOB(DOB), + ); + +end else begin + + wire [17:0] DIA = PORT_A_WR_DATA; + wire [17:0] DIB = PORT_B_WR_DATA; + wire [17:0] DOA; + wire [17:0] DOB; + + assign PORT_A_RD_DATA = DOA; + assign PORT_B_RD_DATA = DOB; + + DPX9B #( + `INIT(init_slice_x9) + .READ_MODE0(1'b0), + .READ_MODE1(1'b0), + .WRITE_MODE0(PORT_A_OPTION_WRITE_MODE), + .WRITE_MODE1(PORT_B_OPTION_WRITE_MODE), + .BIT_WIDTH_0(PORT_A_WIDTH), + .BIT_WIDTH_1(PORT_B_WIDTH), + .BLK_SEL_0(3'b000), + .BLK_SEL_1(3'b000), + .RESET_MODE(OPTION_RESET_MODE), + ) _TECHMAP_REPLACE_ ( + .BLKSELA(3'b000), + .BLKSELB(3'b000), + + .CLKA(PORT_A_CLK), + .CEA(PORT_A_CLK_EN), + .WREA(PORT_A_WR_EN), + .RESETA(RSTA), + .OCEA(1'b1), + .ADA(ADA), + .DIA(DIA), + .DOA(DOA), + + .CLKB(PORT_B_CLK), + .CEB(PORT_B_CLK_EN), + .WREB(PORT_B_WR_EN), + .RESETB(RSTB), + .OCEB(1'b1), + .ADB(ADB), + .DIB(DIB), + .DOB(DOB), + ); + +end + +endgenerate + +endmodule + + +module $__GOWIN_SDP_ (...); + +parameter INIT = 0; +parameter OPTION_RESET_MODE = "SYNC"; + +parameter PORT_R_WIDTH = 18; +parameter PORT_W_WIDTH = 18; + +input PORT_R_CLK; +input PORT_R_CLK_EN; +input PORT_R_RD_SRST; +input PORT_R_RD_ARST; +input [13:0] PORT_R_ADDR; +output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA; + +input PORT_W_CLK; +input PORT_W_CLK_EN; +input PORT_W_WR_EN; +input [13:0] PORT_W_ADDR; +input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA; + +`DEF_FUNCS + +wire RST = OPTION_RESET_MODE == "SYNC" ? PORT_R_RD_SRST : PORT_R_RD_ARST; +wire [13:0] ADW = `addrbe_always(PORT_W_WIDTH, PORT_W_ADDR); +wire WRE = PORT_W_CLK_EN & PORT_W_WR_EN; + +generate + +if (PORT_W_WIDTH < 9 || PORT_R_WIDTH < 9) begin + + wire [31:0] DI = `x8_wr_data(PORT_W_WR_DATA); + wire [31:0] DO; + + assign PORT_R_RD_DATA = `x8_rd_data(DO); + + SDPB #( + `INIT(init_slice_x8) + .READ_MODE(1'b0), + .BIT_WIDTH_0(`x8_width(PORT_W_WIDTH)), + .BIT_WIDTH_1(`x8_width(PORT_R_WIDTH)), + .BLK_SEL_0(3'b000), + .BLK_SEL_1(3'b000), + .RESET_MODE(OPTION_RESET_MODE), + ) _TECHMAP_REPLACE_ ( + .BLKSELA(3'b000), + .BLKSELB(3'b000), + + .CLKA(PORT_W_CLK), + .CEA(WRE), + .ADA(ADW), + .DI(DI), + + .CLKB(PORT_R_CLK), + .CEB(PORT_R_CLK_EN), + .RESET(RST), + .OCE(1'b1), + .ADB(PORT_R_ADDR), + .DO(DO), + ); + +end else begin + + wire [35:0] DI = PORT_W_WR_DATA; + wire [35:0] DO; + + assign PORT_R_RD_DATA = DO; + + SDPX9B #( + `INIT(init_slice_x9) + .READ_MODE(1'b0), + .BIT_WIDTH_0(PORT_W_WIDTH), + .BIT_WIDTH_1(PORT_R_WIDTH), + .BLK_SEL_0(3'b000), + .BLK_SEL_1(3'b000), + .RESET_MODE(OPTION_RESET_MODE), + ) _TECHMAP_REPLACE_ ( + .BLKSELA(3'b000), + .BLKSELB(3'b000), + + .CLKA(PORT_W_CLK), + .CEA(WRE), + .ADA(ADW), + .DI(DI), + + .CLKB(PORT_R_CLK), + .CEB(PORT_R_CLK_EN), + .RESET(RST), + .OCE(1'b1), + .ADB(PORT_R_ADDR), + .DO(DO), + ); + +end + +endgenerate + +endmodule diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 8f3553df6..1a55f9f37 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -57,6 +57,9 @@ struct SynthGowinPass : public ScriptPass log(" -nodffe\n"); log(" do not use flipflops with CE in output netlist\n"); log("\n"); + log(" -strict-gw5a-dffs\n"); + log(" use only DFFSE/DFFRE/DFFPE/DFFCE flipflops for the GW5A family\n"); + log("\n"); log(" -nobram\n"); log(" do not use BRAM cells in output netlist\n"); log("\n"); @@ -91,13 +94,16 @@ struct SynthGowinPass : public ScriptPass log(" The following families are supported:\n"); log(" 'gw1n', 'gw2a', 'gw5a'.\n"); log("\n"); + log(" -setundef\n"); + log(" set undriven wires and parameters to zero\n"); + log("\n"); log("The following commands are executed by this synthesis command:\n"); help_script(); log("\n"); } string top_opt, vout_file, json_file, family; - bool retime, nobram, nolutram, flatten, nodffe, nowidelut, abc9, noiopads, noalu, no_rw_check; + bool retime, nobram, nolutram, flatten, nodffe, strict_gw5a_dffs, nowidelut, abc9, noiopads, noalu, no_rw_check, setundef; void clear_flags() override { @@ -109,12 +115,14 @@ struct SynthGowinPass : public ScriptPass flatten = true; nobram = false; nodffe = false; + strict_gw5a_dffs = false; nolutram = false; nowidelut = false; abc9 = true; noiopads = false; noalu = false; no_rw_check = false; + setundef = false; } void execute(std::vector args, RTLIL::Design *design) override @@ -165,6 +173,10 @@ struct SynthGowinPass : public ScriptPass nodffe = true; continue; } + if (args[argidx] == "-strict-gw5a-dffs") { + strict_gw5a_dffs = true; + continue; + } if (args[argidx] == "-noflatten") { flatten = false; continue; @@ -193,6 +205,10 @@ struct SynthGowinPass : public ScriptPass no_rw_check = true; continue; } + if (args[argidx] == "-setundef") { + setundef = true; + continue; + } break; } extra_args(args, argidx, design); @@ -248,7 +264,7 @@ struct SynthGowinPass : public ScriptPass args += " -no-auto-distributed"; } run("memory_libmap -lib +/gowin/lutrams.txt -lib +/gowin/brams.txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)"); - run("techmap -map +/gowin/lutrams_map.v -map +/gowin/brams_map.v"); + run(stringf("techmap -map +/gowin/lutrams_map.v -map +/gowin/brams_map%s.v", family == "gw5a" ? "_gw5a" : "")); } if (check_label("map_ffram")) @@ -276,10 +292,18 @@ struct SynthGowinPass : public ScriptPass if (check_label("map_ffs")) { run("opt_clean"); - if (nodffe) - run("dfflegalize -cell $_DFF_?_ 0 -cell $_SDFF_?P?_ r -cell $_DFF_?P?_ r"); - else - run("dfflegalize -cell $_DFF_?_ 0 -cell $_DFFE_?P_ 0 -cell $_SDFF_?P?_ r -cell $_SDFFE_?P?P_ r -cell $_DFF_?P?_ r -cell $_DFFE_?P?P_ r"); + if (family == "gw5a") { + if (strict_gw5a_dffs) { + run("dfflegalize -cell $_SDFFE_PP?P_ r -cell $_DFFE_PP?P_ r"); + } else { + run("dfflegalize -cell $_DFF_?_ 0 -cell $_SDFFE_PP?P_ r -cell $_DFFE_PP?P_ r"); + } + } else { + if (nodffe) + run("dfflegalize -cell $_DFF_?_ 0 -cell $_SDFF_?P?_ r -cell $_DFF_?P?_ r"); + else + run("dfflegalize -cell $_DFF_?_ 0 -cell $_DFFE_?P_ 0 -cell $_SDFF_?P?_ r -cell $_SDFFE_?P?P_ r -cell $_DFF_?P?_ r -cell $_DFFE_?P?P_ r"); + } run("techmap -map +/gowin/cells_map.v"); run("opt_expr -mux_undef"); run("simplemap"); @@ -305,10 +329,11 @@ struct SynthGowinPass : public ScriptPass { run("techmap -map +/gowin/cells_map.v"); run("opt_lut_ins -tech gowin"); - run("setundef -undriven -params -zero"); + if (setundef || help_mode) + run("setundef -undriven -params -zero", "(only if -setundef)"); run("hilomap -singleton -hicell VCC V -locell GND G"); if (!vout_file.empty() || help_mode) // vendor output requires 1-bit wires - run("splitnets -ports", "(only if -vout used)"); + run("splitnets -ports", "(only if -vout)"); run("clean"); run("autoname"); } diff --git a/tests/liberty/libcache.ys b/tests/liberty/libcache.ys index 04257aa92..8132b3f11 100644 --- a/tests/liberty/libcache.ys +++ b/tests/liberty/libcache.ys @@ -1,5 +1,5 @@ libcache -verbose -libcache -enable busdef.lib +libcache -enable bus*f.lib logger -expect log "Caching is disabled by default." 1 logger -expect log "Caching is enabled for `busdef.lib'." 1 diff --git a/tests/rtlil/bug5424.ys b/tests/rtlil/bug5424.ys new file mode 100644 index 000000000..a0b0638e5 --- /dev/null +++ b/tests/rtlil/bug5424.ys @@ -0,0 +1,12 @@ +read_rtlil <