diff --git a/CHANGELOG b/CHANGELOG index 0a6aab40e..1ebaeb24a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,9 +2,36 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.47 .. Yosys 0.48-dev +Yosys 0.48 .. Yosys 0.49-dev -------------------------- +Yosys 0.47 .. Yosys 0.48 +-------------------------- + * Various + - Removed "read_ilang" deprecated pass. + - Enhanced boxing features in the experimental "abc_new" command. + - Added new Tcl methods for design inspection. + - Added clock enable inference to "dfflibmap". + - Added a Han-Carlson and Sklansky option for $lcu mapping. + + * New commands and options + - Added "-nopeepopt" option to "clk2fflogic" pass. + - Added "-liberty" and "-dont_use" options to "clockgate" pass. + - Added "-ignore_buses" option to "read_liberty" pass. + - Added "-dont_map" option to "techmap" pass. + - Added "-selected" option to "write_json" pass. + - Added "wrapcell" command for creating wrapper modules + around selected cells. + - Added "portarcs" command for deriving propagation timing arcs. + - Added "setenv" command for setting environment variables. + + * Gowin support + - Added "-family" option to "synth_gowin" pass. + - Cell definitions split by family. + + * Verific support + - Improved blackbox support. + Yosys 0.46 .. Yosys 0.47 -------------------------- * Various diff --git a/Makefile b/Makefile index fd8af46e5..e293dd9b8 100644 --- a/Makefile +++ b/Makefile @@ -168,7 +168,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.47+211 +YOSYS_VER := 0.48+0 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -184,7 +184,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 647d61d.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline aaa5347.. | wc -l`/;" Makefile ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) @@ -318,7 +318,7 @@ endif else ifeq ($(CONFIG),mxe) PKG_CONFIG = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-pkg-config CXX = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-g++ -CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -D_POSIX_SOURCE -DYOSYS_MXE_HACKS -Wno-attributes +CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -D_POSIX_SOURCE -Wno-attributes CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) LINKFLAGS := $(filter-out -rdynamic,$(LINKFLAGS)) -s LIBS := $(filter-out -lrt,$(LIBS)) diff --git a/backends/aiger2/aiger.cc b/backends/aiger2/aiger.cc index 141217fe5..c7ed3b81f 100644 --- a/backends/aiger2/aiger.cc +++ b/backends/aiger2/aiger.cc @@ -832,12 +832,8 @@ struct XAigerAnalysis : Index { return false; Cell *driver = bit.wire->driverCell(); - if (!driver->type.isPublic()) - return false; - Module *mod = design->module(driver->type); - log_assert(mod); - if (!mod->has_attribute(ID::abc9_box_id)) + if (!mod || !mod->has_attribute(ID::abc9_box_id)) return false; int max = 1; @@ -870,7 +866,7 @@ struct XAigerAnalysis : Index { HierCursor cursor; for (auto box : top_minfo->found_blackboxes) { Module *def = design->module(box->type); - if (!box->type.isPublic() || (def && !def->has_attribute(ID::abc9_box_id))) + if (!(def && def->has_attribute(ID::abc9_box_id))) for (auto &conn : box->connections_) if (box->output(conn.first)) for (auto bit : conn.second) @@ -885,7 +881,7 @@ struct XAigerAnalysis : Index { for (auto box : top_minfo->found_blackboxes) { Module *def = design->module(box->type); - if (!box->type.isPublic() || (def && !def->has_attribute(ID::abc9_box_id))) + if (!(def && def->has_attribute(ID::abc9_box_id))) for (auto &conn : box->connections_) if (box->input(conn.first)) for (auto bit : conn.second) @@ -1106,7 +1102,7 @@ struct XAigerWriter : AigerWriter { holes_module->ports.push_back(w->name); holes_pis.push_back(w); } - in_conn.append(holes_pis[i]); + in_conn.append(holes_pis[holes_pi_idx]); holes_pi_idx++; } holes_wb->setPort(port_id, in_conn); diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index e09f84033..cc13b3c9c 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -1087,7 +1087,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) return true; } - if (cell->type == ID($_BUF_)) { + if (cell->type.in(ID($_BUF_), ID($buf))) { f << stringf("%s" "assign ", indent.c_str()); dump_sigspec(f, cell->getPort(ID::Y)); f << stringf(" = "); diff --git a/docs/source/conf.py b/docs/source/conf.py index b9a908167..8c8555b71 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -6,7 +6,7 @@ import os project = 'YosysHQ Yosys' author = 'YosysHQ GmbH' copyright ='2024 YosysHQ GmbH' -yosys_ver = "0.47" +yosys_ver = "0.48" # select HTML theme html_theme = 'furo-ys' diff --git a/frontends/aiger2/xaiger.cc b/frontends/aiger2/xaiger.cc index 3d502edf1..616bec9e7 100644 --- a/frontends/aiger2/xaiger.cc +++ b/frontends/aiger2/xaiger.cc @@ -203,7 +203,6 @@ struct Xaiger2Frontend : public Frontend { /* unused box_id = */ read_be32(*f); auto box_seq = read_be32(*f); - log("box_seq=%d boxes.size=%d\n", box_seq, (int) boxes.size()); log_assert(box_seq < boxes.size()); auto [cell, def] = boxes[box_seq]; diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc index 91d390131..b29984ecd 100644 --- a/frontends/liberty/liberty.cc +++ b/frontends/liberty/liberty.cc @@ -572,6 +572,8 @@ struct LibertyFrontend : public Frontend { for (auto &attr : attributes) module->attributes[attr] = 1; + bool simple_comb_cell = true, has_outputs = false; + for (auto node : cell->children) { if (node->id == "pin" && node->args.size() == 1) { @@ -613,6 +615,8 @@ struct LibertyFrontend : public Frontend { if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal")) log_error("Missing or invalid direction for bus %s on cell %s.\n", node->args.at(0).c_str(), log_id(module->name)); + simple_comb_cell = false; + if (dir->value == "internal") continue; @@ -660,6 +664,9 @@ struct LibertyFrontend : public Frontend { { const LibertyAst *dir = node->find("direction"); + if (dir->value == "internal" || dir->value == "inout") + simple_comb_cell = false; + if (flag_lib && dir->value == "internal") continue; @@ -680,8 +687,10 @@ struct LibertyFrontend : public Frontend { continue; } - if (dir && dir->value == "output") + if (dir && dir->value == "output") { + has_outputs = true; wire->port_output = true; + } if (flag_lib) continue; @@ -699,36 +708,35 @@ struct LibertyFrontend : public Frontend { goto skip_cell; } } + simple_comb_cell = false; } else { RTLIL::SigSpec out_sig = parse_func_expr(module, func->value.c_str()); const LibertyAst *three_state = node->find("three_state"); if (three_state) { out_sig = create_tristate(module, out_sig, three_state->value.c_str()); + simple_comb_cell = false; } module->connect(RTLIL::SigSig(wire, out_sig)); } + } - if (flag_unit_delay) { - pool done; + if (node->id == "ff" || node->id == "ff_bank" || + node->id == "latch" || node->id == "latch_bank" || + node->id == "statetable") + simple_comb_cell = false; + } - for (auto timing : node->children) - if (timing->id == "timing" && timing->args.empty()) { - auto type = timing->find("timing_type"); - auto related_pin = timing->find("related_pin"); - if (!type || type->value != "combinational" || !related_pin) - continue; - - Wire *related = module->wire(RTLIL::escape_id(related_pin->value)); - if (!related) - log_error("Failed to find related pin %s for timing of pin %s on %s\n", - related_pin->value.c_str(), log_id(wire), log_id(module)); - - if (done.count(related)) - continue; + if (simple_comb_cell && has_outputs) { + module->set_bool_attribute(ID::abc9_box); + if (flag_unit_delay) { + for (auto wi : module->wires()) + if (wi->port_input) { + for (auto wo : module->wires()) + if (wo->port_output) { RTLIL::Cell *spec = module->addCell(NEW_ID, ID($specify2)); - spec->setParam(ID::SRC_WIDTH, 1); - spec->setParam(ID::DST_WIDTH, 1); + spec->setParam(ID::SRC_WIDTH, wi->width); + spec->setParam(ID::DST_WIDTH, wo->width); spec->setParam(ID::T_FALL_MAX, 1000); spec->setParam(ID::T_FALL_TYP, 1000); spec->setParam(ID::T_FALL_MIN, 1000); @@ -737,11 +745,10 @@ struct LibertyFrontend : public Frontend { spec->setParam(ID::T_RISE_MIN, 1000); spec->setParam(ID::SRC_DST_POL, false); spec->setParam(ID::SRC_DST_PEN, false); - spec->setParam(ID::FULL, false); + spec->setParam(ID::FULL, true); spec->setPort(ID::EN, Const(1, 1)); - spec->setPort(ID::SRC, related); - spec->setPort(ID::DST, wire); - done.insert(related); + spec->setPort(ID::SRC, wi); + spec->setPort(ID::DST, wo); } } } diff --git a/kernel/driver.cc b/kernel/driver.cc index a6b94868e..6565c472c 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -31,6 +31,10 @@ # include #endif +#ifdef YOSYS_ENABLE_TCL +# include +#endif + #include #include #include diff --git a/kernel/tclapi.cc b/kernel/tclapi.cc index e538f2152..5431271d6 100644 --- a/kernel/tclapi.cc +++ b/kernel/tclapi.cc @@ -18,8 +18,9 @@ */ #ifdef YOSYS_ENABLE_TCL -#include "tclTomMath.h" -#include "tclTomMathDecls.h" +#include +#include +#include #endif #include "kernel/yosys.h" diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 08e7842d4..e9c9b8875 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -31,6 +31,10 @@ # include #endif +#ifdef YOSYS_ENABLE_TCL +# include +#endif + #ifdef YOSYS_ENABLE_PLUGINS # include #endif diff --git a/kernel/yosys.h b/kernel/yosys.h index 903540a9e..d0359aea8 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -43,6 +43,10 @@ #include "kernel/rtlil.h" #include "kernel/register.h" +#ifdef YOSYS_ENABLE_TCL +struct Tcl_Interp; +#endif + YOSYS_NAMESPACE_BEGIN void yosys_setup(); diff --git a/kernel/yosys_common.h b/kernel/yosys_common.h index 3007ca694..2530b12db 100644 --- a/kernel/yosys_common.h +++ b/kernel/yosys_common.h @@ -65,29 +65,6 @@ #define FRIEND_TEST(test_case_name, test_name) \ friend class test_case_name##_##test_name##_Test -#ifdef YOSYS_ENABLE_TCL -# include -# ifdef YOSYS_MXE_HACKS -extern Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); -extern Tcl_Interp *Tcl_CreateInterp(void); -extern void Tcl_Preserve(ClientData data); -extern void Tcl_Release(ClientData clientData); -extern int Tcl_InterpDeleted(Tcl_Interp *interp); -extern void Tcl_DeleteInterp(Tcl_Interp *interp); -extern int Tcl_Eval(Tcl_Interp *interp, const char *script); -extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName); -extern void Tcl_Finalize(void); -extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr); -extern const char *Tcl_GetStringResult(Tcl_Interp *interp); -extern Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length); -extern Tcl_Obj *Tcl_NewIntObj(int intValue); -extern Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[]); -extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags); -# endif -# undef CONST -# undef INLINE -#endif - #ifdef _WIN32 # undef NOMINMAX # define NOMINMAX 1 diff --git a/passes/cmds/wrapcell.cc b/passes/cmds/wrapcell.cc index 812de9ebb..0c15848e4 100644 --- a/passes/cmds/wrapcell.cc +++ b/passes/cmds/wrapcell.cc @@ -18,12 +18,37 @@ */ #include "kernel/yosys.h" #include "kernel/celltypes.h" +#include "kernel/sigtools.h" #include "backends/rtlil/rtlil_backend.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -std::optional format(std::string fmt, const dict ¶meters) +bool has_fmt_field(std::string fmt, std::string field_name) +{ + auto it = fmt.begin(); + while (it != fmt.end()) { + if (*it == '{') { + it++; + auto beg = it; + while (it != fmt.end() && *it != '}') it++; + if (it == fmt.end()) + return false; + + if (std::string(beg, it) == field_name) + return true; + } + it++; + } + return false; +} + +struct ContextData { + std::string unused_outputs; +}; + +std::optional format(std::string fmt, const dict ¶meters, + const ContextData &context) { std::stringstream result; @@ -38,13 +63,19 @@ std::optional format(std::string fmt, const dict & return {}; } - auto id = RTLIL::escape_id(std::string(beg, it)); - if (!parameters.count(id)) { - log("Parameter %s referenced in format string '%s' not found\n", log_id(id), fmt.c_str()); - return {}; - } + std::string param_name = {beg, it}; - RTLIL_BACKEND::dump_const(result, parameters.at(id)); + if (param_name == "%unused") { + result << context.unused_outputs; + } else { + auto id = RTLIL::escape_id(std::string(beg, it)); + if (!parameters.count(id)) { + log("Parameter %s referenced in format string '%s' not found\n", log_id(id), fmt.c_str()); + return {}; + } + + RTLIL_BACKEND::dump_const(result, parameters.at(id)); + } } else { result << *it; } @@ -54,6 +85,45 @@ std::optional format(std::string fmt, const dict & return {result.str()}; } +struct Chunk { + IdString port; + int base, len; + + Chunk(IdString id, int base, int len) + : port(id), base(base), len(len) {} + + IdString format(Cell *cell) + { + if (len == cell->getPort(port).size()) + return port; + else if (len == 1) + return stringf("%s[%d]", port.c_str(), base); + else + return stringf("%s[%d:%d]", port.c_str(), base + len - 1, base); + } + + SigSpec sample(Cell *cell) + { + return cell->getPort(port).extract(base, len); + } +}; + +// Joins contiguous runs of bits into a 'Chunk' +std::vector collect_chunks(std::vector> bits) +{ + std::vector ret; + std::sort(bits.begin(), bits.end()); + for (auto it = bits.begin(); it != bits.end();) { + auto sep = it + 1; + for (; sep != bits.end() && + sep->first == it->first && + sep->second == (sep - 1)->second + 1; sep++); + ret.emplace_back(it->first, it->second, sep - it); + it = sep; + } + return ret; +} + struct WrapcellPass : Pass { WrapcellPass() : Pass("wrapcell", "wrap individual cells into new modules") {} @@ -68,6 +138,10 @@ struct WrapcellPass : Pass { log("parameter values as specified in curly brackets. If the named module already\n"); log("exists, it is reused.\n"); log("\n"); + log("If the template contains the special string '{%%unused}', the command tracks\n"); + log("unused output ports -- specialized wrapper modules will be generated per every\n"); + log("distinct set of unused port bits as appearing on any selected cell.\n"); + log("\n"); log(" -setattr \n"); log(" set the given boolean attribute on each created wrapper module\n"); log("\n"); @@ -114,35 +188,81 @@ struct WrapcellPass : Pass { CellTypes ct; ct.setup(); + bool tracking_unused = has_fmt_field(name_fmt, "%unused"); + for (auto module : d->selected_modules()) { - for (auto cell : module->selected_cells()) { - std::optional unescaped_name = format(name_fmt, cell->parameters); - if (!unescaped_name) - log_error("Formatting error when processing cell '%s' in module '%s'\n", - log_id(cell), log_id(module)); + SigPool unused; - IdString name = RTLIL::escape_id(unescaped_name.value()); - - if (d->module(name)) { - cell->type = name; - cell->parameters.clear(); - continue; + for (auto wire : module->wires()) + if (wire->has_attribute(ID::unused_bits)) { + std::string str = wire->get_string_attribute(ID::unused_bits); + for (auto it = str.begin(); it != str.end();) { + auto sep = it; + for (; sep != str.end() && *sep != ' '; sep++); + unused.add(SigBit(wire, std::stoi(std::string(it, sep)))); + for (it = sep; it != str.end() && *it == ' '; it++); } + } + + for (auto cell : module->selected_cells()) { + Module *subm; + Cell *subcell; if (!ct.cell_known(cell->type)) log_error("Non-internal cell type '%s' on cell '%s' in module '%s' unsupported\n", log_id(cell->type), log_id(cell), log_id(module)); - Module *subm = d->addModule(name); - Cell *subcell = subm->addCell("$1", cell->type); + std::vector> unused_outputs, used_outputs; for (auto conn : cell->connections()) { - Wire *w = subm->addWire(conn.first, conn.second.size()); - if (ct.cell_output(cell->type, w->name)) - w->port_output = true; - else - w->port_input = true; - subcell->setPort(conn.first, w); + if (ct.cell_output(cell->type, conn.first)) + for (int i = 0; i < conn.second.size(); i++) { + if (tracking_unused && unused.check(conn.second[i])) + unused_outputs.emplace_back(conn.first, i); + else + used_outputs.emplace_back(conn.first, i); + } } + + ContextData context; + if (!unused_outputs.empty()) { + context.unused_outputs += "_unused"; + for (auto chunk : collect_chunks(unused_outputs)) + context.unused_outputs += "_" + RTLIL::unescape_id(chunk.format(cell)); + } + + std::optional unescaped_name = format(name_fmt, cell->parameters, context); + if (!unescaped_name) + log_error("Formatting error when processing cell '%s' in module '%s'\n", + log_id(cell), log_id(module)); + + IdString name = RTLIL::escape_id(unescaped_name.value()); + if (d->module(name)) + goto replace_cell; + + subm = d->addModule(name); + subcell = subm->addCell("$1", cell->type); + for (auto conn : cell->connections()) { + if (ct.cell_output(cell->type, conn.first)) { + // Insert marker bits as placehodlers which need to be replaced + subcell->setPort(conn.first, SigSpec(RTLIL::Sm, conn.second.size())); + } else { + Wire *w = subm->addWire(conn.first, conn.second.size()); + w->port_input = true; + subcell->setPort(conn.first, w); + } + } + + for (auto chunk : collect_chunks(used_outputs)) { + Wire *w = subm->addWire(chunk.format(cell), chunk.len); + w->port_output = true; + subcell->connections_[chunk.port].replace(chunk.base, w); + } + + for (auto chunk : collect_chunks(unused_outputs)) { + Wire *w = subm->addWire(chunk.format(cell), chunk.len); + subcell->connections_[chunk.port].replace(chunk.base, w); + } + subcell->parameters = cell->parameters; subm->fixup_ports(); @@ -150,7 +270,7 @@ struct WrapcellPass : Pass { if (rule.value_fmt.empty()) { subm->set_bool_attribute(rule.name); } else { - std::optional value = format(rule.value_fmt, cell->parameters); + std::optional value = format(rule.value_fmt, cell->parameters, context); if (!value) log_error("Formatting error when processing cell '%s' in module '%s'\n", @@ -160,8 +280,20 @@ struct WrapcellPass : Pass { } } - cell->type = name; + replace_cell: cell->parameters.clear(); + + dict new_connections; + + for (auto conn : cell->connections()) + if (!ct.cell_output(cell->type, conn.first)) + new_connections[conn.first] = conn.second; + + for (auto chunk : collect_chunks(used_outputs)) + new_connections[chunk.format(cell)] = chunk.sample(cell); + + cell->type = name; + cell->connections_ = new_connections; } } } diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 378f29042..4c7667a43 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -969,13 +969,10 @@ void prep_box(RTLIL::Design *design) if (it == module->attributes.end()) continue; bool box = it->second.as_bool(); - module->attributes.erase(it); if (!box) continue; auto r = module->attributes.insert(ID::abc9_box_id); - if (!r.second) - continue; r.first->second = abc9_box_id++; if (module->get_bool_attribute(ID::abc9_flop)) { @@ -1078,7 +1075,8 @@ void prep_box(RTLIL::Design *design) } ss << log_id(module) << " " << module->attributes.at(ID::abc9_box_id).as_int(); - ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0"); + bool has_model = module->get_bool_attribute(ID::whitebox) || !module->get_bool_attribute(ID::blackbox); + ss << " " << (has_model ? "1" : "0"); ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl; bool first = true; @@ -1096,8 +1094,9 @@ void prep_box(RTLIL::Design *design) ss << std::endl; auto &t = timing.setup_module(module); - if (t.comb.empty()) + if (t.comb.empty() && !outputs.empty() && !inputs.empty()) { log_error("Module '%s' with (* abc9_box *) has no timing (and thus no connectivity) information.\n", log_id(module)); + } for (const auto &o : outputs) { first = true; diff --git a/passes/techmap/abc_new.cc b/passes/techmap/abc_new.cc index eefe34f84..5be823916 100644 --- a/passes/techmap/abc_new.cc +++ b/passes/techmap/abc_new.cc @@ -19,10 +19,29 @@ #include "kernel/register.h" #include "kernel/rtlil.h" +#include "kernel/utils.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +std::vector order_modules(Design *design, std::vector modules) +{ + std::set modules_set(modules.begin(), modules.end()); + TopoSort sort; + + for (auto m : modules) { + sort.node(m); + + for (auto cell : m->cells()) { + Module *submodule = design->module(cell->type); + if (modules_set.count(submodule)) + sort.edge(submodule, m); + } + } + log_assert(sort.sort()); + return sort.sorted; +} + struct AbcNewPass : public ScriptPass { AbcNewPass() : ScriptPass("abc_new", "(experimental) use ABC for SC technology mapping (new)") { @@ -101,6 +120,15 @@ struct AbcNewPass : public ScriptPass { } if (check_label("prep_boxes")) { + if (!help_mode) { + for (auto mod : active_design->selected_whole_modules_warn()) { + if (mod->get_bool_attribute(ID::abc9_box)) { + mod->set_bool_attribute(ID::abc9_box, false); + mod->set_bool_attribute(ID(abc9_deferred_box), true); + } + } + } + run("box_derive"); run("abc9_ops -prep_box"); } @@ -109,7 +137,8 @@ struct AbcNewPass : public ScriptPass { std::vector selected_modules; if (!help_mode) { - selected_modules = active_design->selected_whole_modules_warn(); + selected_modules = order_modules(active_design, + active_design->selected_whole_modules_warn()); active_design->selection_stack.emplace_back(false); } else { selected_modules = {nullptr}; @@ -131,15 +160,36 @@ struct AbcNewPass : public ScriptPass { active_design->selection().select(mod); } + std::string script_save; + if (!help_mode && mod->has_attribute(ID(abc9_script))) { + script_save = active_design->scratchpad_get_string("abc9.script"); + active_design->scratchpad_set_string("abc9.script", + mod->get_string_attribute(ID(abc9_script))); + } + run(stringf(" abc9_ops -write_box %s/input.box", tmpdir.c_str())); run(stringf(" write_xaiger2 -mapping_prep -map2 %s/input.map2 %s/input.xaig", tmpdir.c_str(), tmpdir.c_str())); run(stringf(" abc9_exe %s -cwd %s -box %s/input.box", exe_options.c_str(), tmpdir.c_str(), tmpdir.c_str())); run(stringf(" read_xaiger2 -sc_mapping -module_name %s -map2 %s/input.map2 %s/output.aig", modname.c_str(), tmpdir.c_str(), tmpdir.c_str())); + if (!help_mode && mod->has_attribute(ID(abc9_script))) { + if (script_save.empty()) + active_design->scratchpad_unset("abc9.script"); + else + active_design->scratchpad_set_string("abc9.script", script_save); + } + if (!help_mode) { active_design->selection().selected_modules.clear(); log_pop(); + + if (mod->get_bool_attribute(ID(abc9_deferred_box))) { + mod->set_bool_attribute(ID(abc9_deferred_box), false); + mod->set_bool_attribute(ID::abc9_box, true); + Pass::call_on_module(active_design, mod, "portarcs -draw -write"); + run("abc9_ops -prep_box"); + } } } diff --git a/tests/techmap/dfflibmap-sim.v b/tests/techmap/dfflibmap-sim.v index 1788a683b..42006a211 100644 --- a/tests/techmap/dfflibmap-sim.v +++ b/tests/techmap/dfflibmap-sim.v @@ -20,3 +20,12 @@ always @(posedge CLK, posedge CLEAR, posedge PRESET) assign QN = ~Q; endmodule + +module dffe(input CLK, EN, D, output reg Q, output QN); + +always @(negedge CLK) + if (EN) Q <= D; + +assign QN = ~Q; + +endmodule diff --git a/tests/techmap/dfflibmap.lib b/tests/techmap/dfflibmap.lib index ce460877e..d0cd472c3 100644 --- a/tests/techmap/dfflibmap.lib +++ b/tests/techmap/dfflibmap.lib @@ -5,7 +5,7 @@ library(test) { ff("IQ", "IQN") { next_state : "D"; clocked_on : "!CLK"; - } + } pin(D) { direction : input; } @@ -19,7 +19,7 @@ library(test) { pin(QN) { direction: output; function : "IQN"; - } + } } cell (dffsr) { area : 6; @@ -30,7 +30,7 @@ library(test) { preset : "PRESET"; clear_preset_var1 : L; clear_preset_var2 : L; - } + } pin(D) { direction : input; } @@ -50,6 +50,30 @@ library(test) { pin(QN) { direction: output; function : "IQN"; - } + } + } + cell (dffe) { + area : 6; + ff("IQ", "IQN") { + next_state : "(D&EN) | (IQ&!EN)"; + clocked_on : "!CLK"; + } + pin(D) { + direction : input; + } + pin(EN) { + direction : input; + } + pin(CLK) { + direction : input; + } + pin(Q) { + direction: output; + function : "IQ"; + } + pin(QN) { + direction: output; + function : "IQN"; + } } } diff --git a/tests/techmap/dfflibmap.ys b/tests/techmap/dfflibmap.ys index e9ba31969..77488d60f 100644 --- a/tests/techmap/dfflibmap.ys +++ b/tests/techmap/dfflibmap.ys @@ -1,14 +1,15 @@ read_verilog -icells <