diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc index 178653c41..fb0e070ad 100644 --- a/passes/cmds/check.cc +++ b/passes/cmds/check.cc @@ -63,7 +63,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"); @@ -142,10 +143,10 @@ 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->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr)) || cell->type.begins_with("$_DLATCH_") || cell->type.begins_with("$_DLATCHSR_") - ) { + ) && !cell->get_bool_attribute(ID::always_latch)) { log_warning("Cell %s.%s is a latch of type %s.\n", module, cell, cell->type.unescape()); counter++; } @@ -300,7 +301,8 @@ struct CheckPass : public Pass { if ( nolatches && ( 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_")) && + !cell->get_bool_attribute(ID::always_latch) ) { log_warning("Cell %s.%s is a latch of type %s.\n", module, cell, cell->type.unescape()); counter++; diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc index 1f5f5b9c6..72a9f0f6b 100644 --- a/passes/proc/proc_dlatch.cc +++ b/passes/proc/proc_dlatch.cc @@ -546,11 +546,16 @@ 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 (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 == POLICY_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); @@ -580,6 +585,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 diff --git a/techlibs/efinix/synth_efinix.cc b/techlibs/efinix/synth_efinix.cc index 5bb517112..a35d1d7af 100644 --- a/techlibs/efinix/synth_efinix.cc +++ b/techlibs/efinix/synth_efinix.cc @@ -68,6 +68,7 @@ struct SynthEfinixPass : public ScriptPass 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(" Latches explicitly requested with 'always_latch' are always permitted.\n"); log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -160,7 +161,7 @@ struct SynthEfinixPass : public ScriptPass if (flatten && check_label("flatten", "(unless -noflatten)")) { - run("proc -latches " + (latches == "info" ? std::string("info") : std::string("warn"))); + run("proc -latches " + latches); run("check"); run("flatten"); run("tribuf -logic"); diff --git a/techlibs/fabulous/synth_fabulous.cc b/techlibs/fabulous/synth_fabulous.cc index 49f84294e..7185aafe5 100644 --- a/techlibs/fabulous/synth_fabulous.cc +++ b/techlibs/fabulous/synth_fabulous.cc @@ -115,6 +115,7 @@ struct SynthPass : public ScriptPass { 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(" Latches explicitly requested with 'always_latch' are always permitted.\n"); log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -289,7 +290,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("proc -latches " + latches); } if (check_label("flatten", "(unless -noflatten)")) { diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 07911350e..67774c169 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -122,6 +122,7 @@ struct SynthIce40Pass : public ScriptPass 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(" Latches explicitly requested with 'always_latch' are always permitted.\n"); log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -316,7 +317,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("proc -latches " + latches); } if (check_label("flatten", "(unless -noflatten)")) diff --git a/techlibs/lattice/synth_lattice.cc b/techlibs/lattice/synth_lattice.cc index a6daf8f85..d1f26ecdf 100644 --- a/techlibs/lattice/synth_lattice.cc +++ b/techlibs/lattice/synth_lattice.cc @@ -161,6 +161,7 @@ struct SynthLatticePass : public ScriptPass 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(" Latches explicitly requested with 'always_latch' are always permitted.\n"); log(" (ignored with -asyncprld, which has a latch primitive)\n"); log("\n"); log("\n"); @@ -416,7 +417,7 @@ struct SynthLatticePass : public ScriptPass if (check_label("coarse")) { - run("proc -latches " + ((asyncprld || latches == "info") ? std::string("info") : std::string("warn"))); + run("proc -latches " + (asyncprld ? std::string("info") : latches)); if (flatten || help_mode) { run("check"); run("flatten"); diff --git a/techlibs/nanoxplore/synth_nanoxplore.cc b/techlibs/nanoxplore/synth_nanoxplore.cc index 20919bead..3cc97f8a4 100644 --- a/techlibs/nanoxplore/synth_nanoxplore.cc +++ b/techlibs/nanoxplore/synth_nanoxplore.cc @@ -102,6 +102,7 @@ struct SynthNanoXplorePass : public ScriptPass 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(" Latches explicitly requested with 'always_latch' are always permitted.\n"); log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -263,7 +264,7 @@ struct SynthNanoXplorePass : public ScriptPass if (check_label("coarse")) { - run("proc -latches " + (latches == "info" ? std::string("info") : std::string("warn"))); + run("proc -latches " + latches); if (flatten || help_mode) { run("check"); run("flatten", "(skip if -noflatten)"); diff --git a/techlibs/quicklogic/synth_quicklogic.cc b/techlibs/quicklogic/synth_quicklogic.cc index 8dddff14c..ca38a6f78 100644 --- a/techlibs/quicklogic/synth_quicklogic.cc +++ b/techlibs/quicklogic/synth_quicklogic.cc @@ -77,6 +77,7 @@ struct SynthQuickLogicPass : public ScriptPass { 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(" Latches explicitly requested with 'always_latch' are always permitted.\n"); log(" (only applies to the pp3 family)\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -226,7 +227,7 @@ struct SynthQuickLogicPass : public ScriptPass { } if (check_label("prepare")) { - run("proc -latches " + ((family == "pp3" && latches != "info") ? std::string("warn") : std::string("info"))); + run("proc -latches " + (family == "pp3" ? latches : std::string("info"))); if (flatten) { run("check"); run("flatten", "(unless -noflatten)");