check make always_latch exempt.

This commit is contained in:
nella 2026-07-14 10:39:17 +02:00
parent 0e82bbefe5
commit 391c0e5f89
8 changed files with 26 additions and 10 deletions

View File

@ -63,7 +63,8 @@ struct CheckPass : public Pass {
log(" -nolatches\n"); log(" -nolatches\n");
log(" also check for latch cells ($dlatch, $adlatch, $dlatchsr and their\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(" $_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("\n");
log(" -latchonly\n"); log(" -latchonly\n");
log(" check only for latch cells (as listed under -nolatches), skipping all\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 // latch-only mode only flags latches, skipping the (potentially false-positive mid-flow) undriven/driver/loop checks below
if (latchonly) { if (latchonly) {
for (auto cell : module->cells()) for (auto cell : module->cells())
if ( if ((
cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr)) || 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()); log_warning("Cell %s.%s is a latch of type %s.\n", module, cell, cell->type.unescape());
counter++; counter++;
} }
@ -300,7 +301,8 @@ struct CheckPass : public Pass {
if ( if (
nolatches && ( nolatches && (
cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr)) || 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()); log_warning("Cell %s.%s is a latch of type %s.\n", module, cell, cell->type.unescape());
counter++; counter++;

View File

@ -546,11 +546,16 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc, LatchPolicy policy)
else else
cell = db.module->addDlatch(NEW_ID, en, rhs, lhs); cell = db.module->addDlatch(NEW_ID, en, rhs, lhs);
cell->set_src_attribute(src); 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); db.generated_dlatches.insert(cell);
if (proc->get_bool_attribute(ID::always_comb)) if (proc->get_bool_attribute(ID::always_comb))
log_error("Latch inferred for signal `%s.%s' from always_comb process `%s.%s'.\n", 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()); 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) else if (policy == POLICY_ERROR)
log_error("Latch inferred for signal `%s.%s' from process `%s.%s': %s\n", 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); 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 <info|warn|error>\n"); log(" -latches <info|warn|error>\n");
log(" controls how the inference of a latch is reported. Alternatively, one\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(" 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"); log("\n");
} }
void execute(std::vector<std::string> args, RTLIL::Design *design) override void execute(std::vector<std::string> args, RTLIL::Design *design) override

View File

@ -68,6 +68,7 @@ struct SynthEfinixPass : public ScriptPass
log(" dedicated hardware primitive and are implemented using LUTs\n"); log(" dedicated hardware primitive and are implemented using LUTs\n");
log(" instead. 'error' (the default) aborts synthesis, 'warn' only\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(" 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("\n"); log("\n");
log("The following commands are executed by this synthesis command:\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)")) 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("check");
run("flatten"); run("flatten");
run("tribuf -logic"); run("tribuf -logic");

View File

@ -115,6 +115,7 @@ struct SynthPass : public ScriptPass {
log(" dedicated hardware primitive and are implemented using LUTs\n"); log(" dedicated hardware primitive and are implemented using LUTs\n");
log(" instead. 'error' (the default) aborts synthesis, 'warn' only\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(" 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("\n"); log("\n");
log("The following commands are executed by this synthesis command:\n"); log("The following commands are executed by this synthesis command:\n");
@ -289,7 +290,7 @@ struct SynthPass : public ScriptPass {
run("hierarchy -check"); run("hierarchy -check");
} else } else
run(stringf("hierarchy -check -top %s", top_module)); 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)")) { if (check_label("flatten", "(unless -noflatten)")) {

View File

@ -122,6 +122,7 @@ struct SynthIce40Pass : public ScriptPass
log(" dedicated hardware primitive and are implemented using LUTs\n"); log(" dedicated hardware primitive and are implemented using LUTs\n");
log(" instead. 'error' (the default) aborts synthesis, 'warn' only\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(" 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("\n"); log("\n");
log("The following commands are executed by this synthesis command:\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("read_verilog " + define + " -lib -specify +/ice40/cells_sim.v");
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt)); run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt));
run("proc -latches " + (latches == "info" ? std::string("info") : std::string("warn"))); run("proc -latches " + latches);
} }
if (check_label("flatten", "(unless -noflatten)")) if (check_label("flatten", "(unless -noflatten)"))

View File

@ -161,6 +161,7 @@ struct SynthLatticePass : public ScriptPass
log(" dedicated hardware primitive and are implemented using LUTs\n"); log(" dedicated hardware primitive and are implemented using LUTs\n");
log(" instead. 'error' (the default) aborts synthesis, 'warn' only\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(" 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(" (ignored with -asyncprld, which has a latch primitive)\n");
log("\n"); log("\n");
log("\n"); log("\n");
@ -416,7 +417,7 @@ struct SynthLatticePass : public ScriptPass
if (check_label("coarse")) 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) { if (flatten || help_mode) {
run("check"); run("check");
run("flatten"); run("flatten");

View File

@ -102,6 +102,7 @@ struct SynthNanoXplorePass : public ScriptPass
log(" dedicated hardware primitive and are implemented using LUTs\n"); log(" dedicated hardware primitive and are implemented using LUTs\n");
log(" instead. 'error' (the default) aborts synthesis, 'warn' only\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(" 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("\n"); log("\n");
log("The following commands are executed by this synthesis command:\n"); log("The following commands are executed by this synthesis command:\n");
@ -263,7 +264,7 @@ struct SynthNanoXplorePass : public ScriptPass
if (check_label("coarse")) if (check_label("coarse"))
{ {
run("proc -latches " + (latches == "info" ? std::string("info") : std::string("warn"))); run("proc -latches " + latches);
if (flatten || help_mode) { if (flatten || help_mode) {
run("check"); run("check");
run("flatten", "(skip if -noflatten)"); run("flatten", "(skip if -noflatten)");

View File

@ -77,6 +77,7 @@ struct SynthQuickLogicPass : public ScriptPass {
log(" dedicated hardware primitive and are implemented using LUTs\n"); log(" dedicated hardware primitive and are implemented using LUTs\n");
log(" instead. 'error' (the default) aborts synthesis, 'warn' only\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(" 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(" (only applies to the pp3 family)\n");
log("\n"); log("\n");
log("The following commands are executed by this synthesis command:\n"); log("The following commands are executed by this synthesis command:\n");
@ -226,7 +227,7 @@ struct SynthQuickLogicPass : public ScriptPass {
} }
if (check_label("prepare")) { 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) { if (flatten) {
run("check"); run("check");
run("flatten", "(unless -noflatten)"); run("flatten", "(unless -noflatten)");