diff --git a/docs/source/using_yosys/verilog.rst b/docs/source/using_yosys/verilog.rst index ef52bfc25..c503bd182 100644 --- a/docs/source/using_yosys/verilog.rst +++ b/docs/source/using_yosys/verilog.rst @@ -172,7 +172,10 @@ Verilog Attributes and non-standard features - The frontend sets attributes ``always_comb``, ``always_latch`` and ``always_ff`` on processes derived from SystemVerilog style always blocks according to the type of the always. These are checked for correctness in - ``proc_dlatch``. + ``proc_dlatch``. Latches inferred from ``always_latch`` processes are exempt + from the ``proc -latches `` reporting policy, and the + generated latch cells carry the ``always_latch`` attribute, which also + exempts them from `check` ``-nolatches``. - The cell attribute ``wildcard_port_conns`` represents wildcard port connections (SystemVerilog ``.*``). These are resolved to concrete connections diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc index 02c9fcdcb..3006af658 100644 --- a/passes/cmds/check.cc +++ b/passes/cmds/check.cc @@ -65,7 +65,8 @@ struct CheckPass : public Pass { log(" -nolatches\n"); log(" also check for latch cells ($dlatch, $adlatch, $dlatchsr and their\n"); log(" $_DLATCH_*/$_DLATCHSR_* mappings) remaining in the design. Use this\n"); - log(" before techmapping in flows that must not emit latches.\n"); + log(" before techmapping in flows that must not emit latches. Cells marked\n"); + log(" with the 'always_latch' attribute are not reported.\n"); log("\n"); log(" -latchonly\n"); log(" check only for latch cells (as listed under -nolatches), skipping all\n"); @@ -144,10 +145,9 @@ struct CheckPass : public Pass { // latch-only mode only flags latches, skipping the (potentially false-positive mid-flow) undriven/driver/loop checks below if (latchonly) { for (auto cell : module->cells()) - if ( + if (!cell->get_bool_attribute(ID::always_latch) && ( cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr)) || - cell->type.begins_with("$_DLATCH_") || cell->type.begins_with("$_DLATCHSR_") - ) { + cell->type.begins_with("$_DLATCH_") || cell->type.begins_with("$_DLATCHSR_"))) { log_warning("Cell %s.%s is a latch of type %s.\n", module, cell, cell->type.unescape()); counter++; } @@ -314,7 +314,7 @@ struct CheckPass : public Pass { } if ( - nolatches && ( + nolatches && !cell->get_bool_attribute(ID::always_latch) && ( cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr)) || cell->type.begins_with("$_DLATCH_") || cell->type.begins_with("$_DLATCHSR_")) ) { diff --git a/passes/proc/CMakeLists.txt b/passes/proc/CMakeLists.txt index b68f7c3d6..98ce8f775 100644 --- a/passes/proc/CMakeLists.txt +++ b/passes/proc/CMakeLists.txt @@ -23,6 +23,7 @@ yosys_pass(proc_mux ) yosys_pass(proc_dlatch proc_dlatch.cc + proc_dlatch.h ) yosys_pass(proc_dff proc_dff.cc diff --git a/passes/proc/proc.cc b/passes/proc/proc.cc index d781d9047..1f25c5608 100644 --- a/passes/proc/proc.cc +++ b/passes/proc/proc.cc @@ -69,7 +69,7 @@ struct ProcPass : public Pass { log(" -noopt\n"); log(" Will omit the opt_expr pass.\n"); log("\n"); - log(" -latches \n"); + log(" -latches \n"); log(" controls how the inference of a latch is reported.\n"); log("\n"); } diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc index 1f5f5b9c6..76a719b04 100644 --- a/passes/proc/proc_dlatch.cc +++ b/passes/proc/proc_dlatch.cc @@ -22,6 +22,7 @@ #include "kernel/ffinit.h" #include "kernel/consteval.h" #include "kernel/log.h" +#include "passes/proc/proc_dlatch.h" #include #include #include @@ -416,12 +417,6 @@ struct proc_dlatch_db_t } }; -enum LatchPolicy { - POLICY_INFO, - POLICY_WARN, - POLICY_ERROR -}; - void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc, LatchPolicy policy) { RTLIL::SigSig latches_bits, nolatches_bits; @@ -546,15 +541,20 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc, LatchPolicy policy) else cell = db.module->addDlatch(NEW_ID, en, rhs, lhs); cell->set_src_attribute(src); + if (proc->get_bool_attribute(ID::always_latch)) + cell->set_bool_attribute(ID::always_latch); db.generated_dlatches.insert(cell); if (proc->get_bool_attribute(ID::always_comb)) log_error("Latch inferred for signal `%s.%s' from always_comb process `%s.%s'.\n", db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str()); - else if (policy == POLICY_ERROR) + else if (proc->get_bool_attribute(ID::always_latch)) + log("Latch inferred for signal `%s.%s' from always_latch process `%s.%s': %s\n", + db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str(), cell); + else if (policy == LatchPolicy::Error) log_error("Latch inferred for signal `%s.%s' from process `%s.%s': %s\n", db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str(), cell); - else if (policy == POLICY_WARN) + else if (policy == LatchPolicy::Warn) log_warning("Latch inferred for signal `%s.%s' from process `%s.%s': %s\n", db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str(), cell); else @@ -580,6 +580,9 @@ struct ProcDlatchPass : public Pass { log(" -latches \n"); log(" controls how the inference of a latch is reported. Alternatively, one\n"); log(" can use the 'proc.latches' scratchpad variable. Defaults to 'warn'.\n"); + log(" Latches requested explicitly with 'always_latch' processes are exempt\n"); + log(" from this policy and always reported at info level. The generated\n"); + log(" latch cells carry the 'always_latch' attribute.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) override @@ -602,13 +605,7 @@ struct ProcDlatchPass : public Pass { policy_str = design->scratchpad_get_string("proc.latches", "warn"); LatchPolicy policy; - if (policy_str == "info") - policy = POLICY_INFO; - else if (policy_str == "warn") - policy = POLICY_WARN; - else if (policy_str == "error") - policy = POLICY_ERROR; - else + if (!latch_policy_from_string(policy_str, policy)) log_cmd_error("Invalid value '%s' for -latches (expected info|warn|error).\n", policy_str.c_str()); for (auto mod : design->all_selected_modules()) { diff --git a/passes/proc/proc_dlatch.h b/passes/proc/proc_dlatch.h new file mode 100644 index 000000000..25bb4d134 --- /dev/null +++ b/passes/proc/proc_dlatch.h @@ -0,0 +1,67 @@ +#ifndef PROC_DLATCH_H +#define PROC_DLATCH_H + +#include "kernel/yosys_common.h" +#include "kernel/log.h" + +YOSYS_NAMESPACE_BEGIN + +enum class LatchPolicy { + Info, + Warn, + Error +}; + +inline bool latch_policy_from_string(const std::string &str, LatchPolicy &policy) +{ + if (str == "info") + policy = LatchPolicy::Info; + else if (str == "warn") + policy = LatchPolicy::Warn; + else if (str == "error") + policy = LatchPolicy::Error; + else + return false; + return true; +} + +inline const char *latch_policy_str(LatchPolicy policy) +{ + switch (policy) { + case LatchPolicy::Info: return "info"; + case LatchPolicy::Warn: return "warn"; + default: return "error"; + } +} + +// shared -latches option handling for synth_* passes +struct SynthLatchesConfig { + LatchPolicy policy = LatchPolicy::Error; + + bool parse(const std::vector &args, size_t &idx) + { + if (args[idx] == "-latches" && idx+1 < args.size()) { + if (!latch_policy_from_string(args[++idx], policy)) + log_cmd_error("Invalid value '%s' for -latches (expected info|warn|error).\n", args[idx].c_str()); + return true; + } + return false; + } + + const char *str() const { return latch_policy_str(policy); } + + static const char *help() + { + return + " -latches \n" + " select the behaviour for latches that cannot be mapped to a\n" + " dedicated hardware primitive and are implemented using LUTs\n" + " instead. 'error' (the default) aborts synthesis, 'warn' only\n" + " prints a warning, and 'info' permits them with an info-level message.\n" + " Latches explicitly requested with 'always_latch' are always permitted.\n"; + } +}; + +YOSYS_NAMESPACE_END + +#endif diff --git a/techlibs/analogdevices/synth_analogdevices.cc b/techlibs/analogdevices/synth_analogdevices.cc index 588a29675..2dff87308 100644 --- a/techlibs/analogdevices/synth_analogdevices.cc +++ b/techlibs/analogdevices/synth_analogdevices.cc @@ -263,7 +263,7 @@ struct SynthAnalogDevicesPass : public ScriptPass } if (check_label("prepare")) { - run("proc"); + run("proc -latches error"); if (flatten || help_mode) { run("check"); run("flatten", "(with '-flatten')"); @@ -430,6 +430,7 @@ struct SynthAnalogDevicesPass : public ScriptPass } if (check_label("map_ffs")) { + run("check -latchonly -assert"); run("dfflegalize -cell $_DFFE_?P?P_ r -cell $_SDFFE_?P?P_ r"); if (dff || help_mode) run("zinit -all w:* t:$_SDFFE_*", "('-dff' only)"); diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index f4c3118bd..3e740881c 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -78,7 +78,7 @@ struct SynthPass : public ScriptPass { log(" -nordff\n"); log(" passed to 'memory'. prohibits merging of FFs into memory read ports\n"); log("\n"); - log(" -latches \n"); + log(" -latches \n"); log(" controls how the inference of a latch is reported.\n"); log("\n"); log(" -noshare\n"); diff --git a/techlibs/efinix/synth_efinix.cc b/techlibs/efinix/synth_efinix.cc index 5ccde173a..ca50f1e37 100644 --- a/techlibs/efinix/synth_efinix.cc +++ b/techlibs/efinix/synth_efinix.cc @@ -22,6 +22,7 @@ #include "kernel/celltypes.h" #include "kernel/rtlil.h" #include "kernel/log.h" +#include "passes/proc/proc_dlatch.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -60,11 +61,7 @@ struct SynthEfinixPass : public ScriptPass log(" -nobram\n"); log(" do not use EFX_RAM_5K cells in output netlist\n"); log("\n"); - log(" -latches \n"); - log(" select the behaviour for latches that cannot be mapped to a\n"); - log(" dedicated hardware primitive and are implemented using LUTs\n"); - log(" instead. 'error' (the default) aborts synthesis, 'warn' only\n"); - log(" prints a warning, and 'info' permits them with an info-level message.\n"); + log("%s", SynthLatchesConfig::help()); log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -72,7 +69,8 @@ struct SynthEfinixPass : public ScriptPass log("\n"); } - string top_opt, edif_file, json_file, latches; + string top_opt, edif_file, json_file; + SynthLatchesConfig latches; bool flatten, nobram; void clear_flags() override @@ -82,7 +80,7 @@ struct SynthEfinixPass : public ScriptPass json_file = ""; flatten = true; nobram = false; - latches = "error"; + latches = SynthLatchesConfig(); } void execute(std::vector args, RTLIL::Design *design) override @@ -125,18 +123,14 @@ struct SynthEfinixPass : public ScriptPass nobram = true; continue; } - if (args[argidx] == "-latches" && argidx+1 < args.size()) { - latches = args[++argidx]; + if (latches.parse(args, argidx)) continue; - } break; } extra_args(args, argidx, design); if (!design->full_selection()) log_cmd_error("This command only operates on fully selected designs!\n"); - if (latches != "info" && latches != "warn" && latches != "error") - log_cmd_error("Invalid value '%s' for -latches (expected info, warn or error)\n", latches.c_str()); log_header(design, "Executing SYNTH_EFINIX pass.\n"); log_push(); @@ -156,7 +150,7 @@ struct SynthEfinixPass : public ScriptPass if (flatten && check_label("flatten", "(unless -noflatten)")) { - run("proc -latches " + (latches == "info" ? std::string("info") : std::string("warn"))); + run(stringf("proc -latches %s", latches.str())); run("check"); run("flatten"); run("tribuf -logic"); @@ -197,7 +191,7 @@ struct SynthEfinixPass : public ScriptPass if (check_label("map_ffs")) { run("dfflegalize -cell $_DFFE_????_ 0 -cell $_SDFFE_????_ 0 -cell $_SDFFCE_????_ 0 -cell $_DLATCH_?_ x"); - if (latches == "error" || help_mode) + if (latches.policy == LatchPolicy::Error || help_mode) run("check -latchonly -assert", "(only if -latches error, the default)"); run("techmap -D NO_LUT -map +/efinix/cells_map.v"); run("opt_expr -mux_undef"); diff --git a/techlibs/fabulous/synth_fabulous.cc b/techlibs/fabulous/synth_fabulous.cc index 2e5fbd104..9391b0871 100644 --- a/techlibs/fabulous/synth_fabulous.cc +++ b/techlibs/fabulous/synth_fabulous.cc @@ -21,6 +21,7 @@ #include "kernel/log.h" #include "kernel/register.h" #include "kernel/rtlil.h" +#include "passes/proc/proc_dlatch.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -110,11 +111,7 @@ struct SynthPass : public ScriptPass { log(" read/write collision\" (same result as setting the no_rw_check\n"); log(" attribute on all memories).\n"); log("\n"); - log(" -latches \n"); - log(" select the behaviour for latches that cannot be mapped to a\n"); - log(" dedicated hardware primitive and are implemented using LUTs\n"); - log(" instead. 'error' (the default) aborts synthesis, 'warn' only\n"); - log(" prints a warning, and 'info' permits them with an info-level message.\n"); + log("%s", SynthLatchesConfig::help()); log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -122,7 +119,8 @@ struct SynthPass : public ScriptPass { log("\n"); } - string top_module, json_file, fsm_opts, memory_opts, carry_mode, cells_map, arith_map, clkbuf_map, multiplier_map, latches; + string top_module, json_file, fsm_opts, memory_opts, carry_mode, cells_map, arith_map, clkbuf_map, multiplier_map; + SynthLatchesConfig latches; std::vector extra_plib, extra_map, extra_mlibmap; std::vector> extra_ffs; @@ -141,7 +139,7 @@ struct SynthPass : public ScriptPass { carry_mode = "none"; flatten = true; json_file = ""; - latches = "error"; + latches = SynthLatchesConfig(); } void execute(std::vector args, RTLIL::Design *design) override @@ -251,18 +249,14 @@ struct SynthPass : public ScriptPass { flatten = false; continue; } - if (args[argidx] == "-latches" && argidx+1 < args.size()) { - latches = args[++argidx]; + if (latches.parse(args, argidx)) continue; - } break; } extra_args(args, argidx, design); if (!design->full_selection()) log_cmd_error("This command only operates on fully selected designs!\n"); - if (latches != "info" && latches != "warn" && latches != "error") - log_cmd_error("Invalid value '%s' for -latches (expected info, warn or error)\n", latches.c_str()); log_header(design, "Executing SYNTH_FABULOUS pass.\n"); log_push(); @@ -290,7 +284,7 @@ struct SynthPass : public ScriptPass { run("hierarchy -check"); } else run(stringf("hierarchy -check -top %s", top_module)); - run("proc -latches " + (latches == "info" ? std::string("info") : std::string("warn"))); + run(stringf("proc -latches %s", latches.str())); } if (check_label("flatten", "(unless -noflatten)")) { @@ -399,7 +393,7 @@ struct SynthPass : public ScriptPass { dff_str += stringf(" -cell %s %s", cell, init); run(dff_str); } - if (latches == "error" || help_mode) + if (latches.policy == LatchPolicy::Error || help_mode) run("check -latchonly -assert", "(only if -latches error, the default)"); run("opt_merge"); } diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index a41e39ae0..de80fecc1 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -21,6 +21,7 @@ #include "kernel/celltypes.h" #include "kernel/rtlil.h" #include "kernel/log.h" +#include "passes/proc/proc_dlatch.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -105,11 +106,7 @@ struct SynthIce40Pass : public ScriptPass log(" read/write collision\" (same result as setting the no_rw_check\n"); log(" attribute on all memories).\n"); log("\n"); - log(" -latches \n"); - log(" select the behaviour for latches that cannot be mapped to a\n"); - log(" dedicated hardware primitive and are implemented using LUTs\n"); - log(" instead. 'error' (the default) aborts synthesis, 'warn' only\n"); - log(" prints a warning, and 'info' permits them with an info-level message.\n"); + log("%s", SynthLatchesConfig::help()); log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -117,7 +114,8 @@ struct SynthIce40Pass : public ScriptPass log("\n"); } - string top_opt, blif_file, edif_file, json_file, device_opt, latches; + string top_opt, blif_file, edif_file, json_file, device_opt; + SynthLatchesConfig latches; bool nocarry, nodffe, nobram, spram, dsp, flatten, noabc, vpr, dff, no_rw_check; int min_ce_use; @@ -138,7 +136,7 @@ struct SynthIce40Pass : public ScriptPass vpr = false; device_opt = "hx"; no_rw_check = false; - latches = "error"; + latches = SynthLatchesConfig(); } void execute(std::vector args, RTLIL::Design *design) override @@ -241,10 +239,8 @@ struct SynthIce40Pass : public ScriptPass no_rw_check = true; continue; } - if (args[argidx] == "-latches" && argidx+1 < args.size()) { - latches = args[++argidx]; + if (latches.parse(args, argidx)) continue; - } break; } extra_args(args, argidx, design); @@ -253,8 +249,6 @@ struct SynthIce40Pass : public ScriptPass log_cmd_error("This command only operates on fully selected designs!\n"); if (device_opt != "hx" && device_opt != "lp" && device_opt !="u") log_cmd_error("Invalid or no device specified: '%s'\n", device_opt); - if (latches != "info" && latches != "warn" && latches != "error") - log_cmd_error("Invalid value '%s' for -latches (expected info, warn or error)\n", latches.c_str()); log_header(design, "Executing SYNTH_ICE40 pass.\n"); log_push(); @@ -283,7 +277,7 @@ struct SynthIce40Pass : public ScriptPass { run("read_verilog " + define + " -lib -specify +/ice40/cells_sim.v"); run(stringf("hierarchy -check %s", help_mode ? "-top " : top_opt)); - run("proc -latches " + (latches == "info" ? std::string("info") : std::string("warn"))); + run(stringf("proc -latches %s", latches.str())); } if (check_label("flatten", "(unless -noflatten)")) @@ -384,7 +378,7 @@ struct SynthIce40Pass : public ScriptPass if (check_label("map_luts")) { - if (latches == "error" || help_mode) + if (latches.policy == LatchPolicy::Error || help_mode) run("check -latchonly -assert", "(only if -latches error, the default)"); run("techmap -map +/ice40/latches_map.v"); if (noabc || help_mode) { diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc index f5842ba6e..a859544cf 100644 --- a/techlibs/intel_alm/synth_intel_alm.cc +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -183,7 +183,7 @@ struct SynthIntelALMPass : public ScriptPass { } if (check_label("coarse")) { - run("proc"); + run("proc -latches error"); if (flatten || help_mode) { run("check"); run("flatten", "(skip if -noflatten)"); @@ -241,6 +241,7 @@ struct SynthIntelALMPass : public ScriptPass { } if (check_label("map_ffs")) { + run("check -latchonly -assert"); run("techmap"); run("dfflegalize -cell $_DFFE_PN0P_ 0 -cell $_SDFFCE_PP0P_ 0"); run("techmap -map +/intel_alm/common/dff_map.v"); diff --git a/techlibs/lattice/synth_lattice.cc b/techlibs/lattice/synth_lattice.cc index d789945e5..4162b2448 100644 --- a/techlibs/lattice/synth_lattice.cc +++ b/techlibs/lattice/synth_lattice.cc @@ -22,6 +22,7 @@ #include "kernel/celltypes.h" #include "kernel/rtlil.h" #include "kernel/log.h" +#include "passes/proc/proc_dlatch.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -147,11 +148,7 @@ struct SynthLatticePass : public ScriptPass log(" implement constant comparisons in soft logic, do not involve\n"); log(" hard carry chains\n"); log("\n"); - log(" -latches \n"); - log(" select the behaviour for latches that cannot be mapped to a\n"); - log(" dedicated hardware primitive and are implemented using LUTs\n"); - log(" instead. 'error' (the default) aborts synthesis, 'warn' only\n"); - log(" prints a warning, and 'info' permits them with an info-level message.\n"); + log("%s", SynthLatchesConfig::help()); log(" (ignored with -asyncprld, which has a latch primitive)\n"); log("\n"); log("\n"); @@ -160,7 +157,8 @@ struct SynthLatticePass : public ScriptPass log("\n"); } - string top_opt, edif_file, json_file, family, latches; + string top_opt, edif_file, json_file, family; + SynthLatchesConfig latches; bool noccu2, nodffe, nobram, nolutram, nowidelut, asyncprld, flatten, dff, iopad, nodsp, no_rw_check, have_dsp; bool cmp2softlogic; string postfix, arith_map, brams_map, dsp_map, cells_map, map_ram_default; @@ -184,7 +182,7 @@ struct SynthLatticePass : public ScriptPass iopad = false; nodsp = false; no_rw_check = false; - latches = "error"; + latches = SynthLatchesConfig(); postfix = ""; arith_map = ""; brams_map = ""; @@ -310,10 +308,8 @@ struct SynthLatticePass : public ScriptPass cmp2softlogic = true; continue; } - if (args[argidx] == "-latches" && argidx+1 < args.size()) { - latches = args[++argidx]; + if (latches.parse(args, argidx)) continue; - } break; } extra_args(args, argidx, design); @@ -321,9 +317,6 @@ struct SynthLatticePass : public ScriptPass if (family.empty()) log_cmd_error("Lattice family parameter must be set.\n"); - if (latches != "info" && latches != "warn" && latches != "error") - log_cmd_error("Invalid value '%s' for -latches (expected info, warn or error)\n", latches.c_str()); - if (family == "ecp5") { postfix = "_ecp5"; arith_map = "_ccu2c"; @@ -394,7 +387,7 @@ struct SynthLatticePass : public ScriptPass if (check_label("coarse")) { - run("proc -latches " + ((asyncprld || latches == "info") ? std::string("info") : std::string("warn"))); + run(stringf("proc -latches %s", asyncprld ? "info" : latches.str())); if (flatten || help_mode) { run("check"); run("flatten"); @@ -530,7 +523,7 @@ struct SynthLatticePass : public ScriptPass if (check_label("map_luts")) { if (!asyncprld || help_mode) { - if (latches == "error" || help_mode) + if (latches.policy == LatchPolicy::Error || help_mode) run("check -latchonly -assert", "(skip if -asyncprld; only if -latches error, the default)"); run("techmap -map +/lattice/latches_map.v", "(skip if -asyncprld)"); } diff --git a/techlibs/nanoxplore/synth_nanoxplore.cc b/techlibs/nanoxplore/synth_nanoxplore.cc index 9612ea759..d6134d2d2 100644 --- a/techlibs/nanoxplore/synth_nanoxplore.cc +++ b/techlibs/nanoxplore/synth_nanoxplore.cc @@ -22,6 +22,7 @@ #include "kernel/celltypes.h" #include "kernel/rtlil.h" #include "kernel/log.h" +#include "passes/proc/proc_dlatch.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -94,11 +95,7 @@ struct SynthNanoXplorePass : public ScriptPass log(" read/write collision\" (same result as setting the no_rw_check\n"); log(" attribute on all memories).\n"); log("\n"); - log(" -latches \n"); - log(" select the behaviour for latches that cannot be mapped to a\n"); - log(" dedicated hardware primitive and are implemented using LUTs\n"); - log(" instead. 'error' (the default) aborts synthesis, 'warn' only\n"); - log(" prints a warning, and 'info' permits them with an info-level message.\n"); + log("%s", SynthLatchesConfig::help()); log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -106,7 +103,8 @@ struct SynthNanoXplorePass : public ScriptPass log("\n"); } - string top_opt, json_file, family, latches; + string top_opt, json_file, family; + SynthLatchesConfig latches; bool flatten, nocy, nodffe, norfram, nobram, noiopad, no_rw_check; std::string postfix; int min_ce_use, min_srst_use; @@ -126,7 +124,7 @@ struct SynthNanoXplorePass : public ScriptPass postfix = ""; min_ce_use = 8; min_srst_use = 8; - latches = "error"; + latches = SynthLatchesConfig(); } void execute(std::vector args, RTLIL::Design *design) override @@ -205,17 +203,12 @@ struct SynthNanoXplorePass : public ScriptPass no_rw_check = true; continue; } - if (args[argidx] == "-latches" && argidx+1 < args.size()) { - latches = args[++argidx]; + if (latches.parse(args, argidx)) continue; - } break; } extra_args(args, argidx, design); - if (latches != "info" && latches != "warn" && latches != "error") - log_cmd_error("Invalid value '%s' for -latches (expected info, warn or error)\n", latches.c_str()); - if (family.empty()) { //log_warning("NanoXplore family not set, setting it to NG-ULTRA.\n"); family = "ultra"; @@ -259,7 +252,7 @@ struct SynthNanoXplorePass : public ScriptPass if (check_label("coarse")) { - run("proc -latches " + (latches == "info" ? std::string("info") : std::string("warn"))); + run(stringf("proc -latches %s", latches.str())); if (flatten || help_mode) { run("check"); run("flatten", "(skip if -noflatten)"); @@ -335,7 +328,7 @@ struct SynthNanoXplorePass : public ScriptPass dfflegalize_args += stringf(" -cell $_DLATCH_?_ x -mince %d -minsrst %d", min_ce_use, min_srst_use); run("dfflegalize" + dfflegalize_args,"($_*DFFE_* only if not -nodffe)"); run("opt_merge"); - if (latches == "error" || help_mode) + if (latches.policy == LatchPolicy::Error || help_mode) run("check -latchonly -assert", "(only if -latches error, the default)"); run("techmap -map +/nanoxplore/latches_map.v"); run("techmap -map +/nanoxplore/cells_map.v"); diff --git a/techlibs/quicklogic/synth_quicklogic.cc b/techlibs/quicklogic/synth_quicklogic.cc index 8cee6d9c4..cf827fe3d 100644 --- a/techlibs/quicklogic/synth_quicklogic.cc +++ b/techlibs/quicklogic/synth_quicklogic.cc @@ -21,6 +21,7 @@ #include "kernel/log.h" #include "kernel/register.h" #include "kernel/rtlil.h" +#include "passes/proc/proc_dlatch.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -68,11 +69,7 @@ struct SynthQuickLogicPass : public ScriptPass { log(" write the design to the specified verilog file. writing of an output\n"); log(" file is omitted if this parameter is not specified.\n"); log("\n"); - log(" -latches \n"); - log(" select the behaviour for latches that cannot be mapped to a\n"); - log(" dedicated hardware primitive and are implemented using LUTs\n"); - log(" instead. 'error' (the default) aborts synthesis, 'warn' only\n"); - log(" prints a warning, and 'info' permits them with an info-level message.\n"); + log("%s", SynthLatchesConfig::help()); log(" (only applies to the pp3 family)\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -80,7 +77,8 @@ struct SynthQuickLogicPass : public ScriptPass { log("\n"); } - string top_opt, blif_file, edif_file, family, currmodule, verilog_file, lib_path, latches; + string top_opt, blif_file, edif_file, family, currmodule, verilog_file, lib_path; + SynthLatchesConfig latches; bool inferAdder, nobram, bramTypes, dsp, ioff, flatten; void clear_flags() override @@ -98,7 +96,7 @@ struct SynthQuickLogicPass : public ScriptPass { dsp = true; ioff = true; flatten = true; - latches = "error"; + latches = SynthLatchesConfig(); } void set_scratchpad_defaults(RTLIL::Design *design) { @@ -171,10 +169,8 @@ struct SynthQuickLogicPass : public ScriptPass { flatten = false; continue; } - if (args[argidx] == "-latches" && argidx+1 < args.size()) { - latches = args[++argidx]; + if (latches.parse(args, argidx)) continue; - } break; } extra_args(args, argidx, design); @@ -185,9 +181,6 @@ struct SynthQuickLogicPass : public ScriptPass { if (family != "pp3" && family != "qlf_k6n10f") log_cmd_error("Invalid family specified: '%s'\n", family); - if (latches != "info" && latches != "warn" && latches != "error") - log_cmd_error("Invalid value '%s' for -latches (expected info, warn or error)\n", latches.c_str()); - if (design->scratchpad_get_int("abc9.D", 0) == 0) { log_warning("delay target has not been set via SDC or scratchpad; assuming 12 MHz clock.\n"); design->scratchpad_set_int("abc9.D", 41667); // 12MHz = 83.33.. ns; divided by two to allow for interconnect delay. @@ -221,7 +214,7 @@ struct SynthQuickLogicPass : public ScriptPass { } if (check_label("prepare")) { - run("proc -latches " + ((family == "pp3" && latches != "info") ? std::string("warn") : std::string("info"))); + run(stringf("proc -latches %s", family == "pp3" ? latches.str() : "info")); if (flatten) { run("check"); run("flatten", "(unless -noflatten)"); @@ -325,7 +318,7 @@ struct SynthQuickLogicPass : public ScriptPass { } if (check_label("map_luts", "(for pp3)") && (help_mode || family == "pp3")) { - if (latches == "error" || help_mode) + if (latches.policy == LatchPolicy::Error || help_mode) run("check -latchonly -assert", "(only if -latches error, the default)"); run("techmap -map " + lib_path + family + "/latches_map.v"); run("read_verilog -lib -specify -icells " + lib_path + family + "/abc9_model.v"); diff --git a/tests/proc/proc_latches.ys b/tests/proc/proc_latches.ys index 91749b6a7..ba22bf879 100644 --- a/tests/proc/proc_latches.ys +++ b/tests/proc/proc_latches.ys @@ -22,6 +22,20 @@ logger -check-expected design -reset +# always_latch is exempt +read_verilog -sv <