3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-06-19 07:16:27 +00:00

Add latch inference msg severity option.

This commit is contained in:
nella 2026-06-15 14:17:02 +02:00
parent 8869ce61dc
commit 7473fcf939
4 changed files with 97 additions and 7 deletions

View file

@ -69,10 +69,14 @@ struct ProcPass : public Pass {
log(" -noopt\n");
log(" Will omit the opt_expr pass.\n");
log("\n");
log(" -latches <auto|warn|error>\n");
log(" controls how the inference of a latch is reported.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::string global_arst;
std::string latches;
bool ifxmode = false;
bool nomux = false;
bool noopt = false;
@ -104,6 +108,10 @@ struct ProcPass : public Pass {
norom = true;
continue;
}
if (args[argidx] == "-latches" && argidx+1 < args.size()) {
latches = args[++argidx];
continue;
}
break;
}
extra_args(args, argidx, design);
@ -121,7 +129,10 @@ struct ProcPass : public Pass {
Pass::call(design, "proc_rom");
if (!nomux)
Pass::call(design, ifxmode ? "proc_mux -ifx" : "proc_mux");
Pass::call(design, "proc_dlatch");
if (latches.empty())
Pass::call(design, "proc_dlatch");
else
Pass::call(design, "proc_dlatch -latches " + latches);
Pass::call(design, "proc_dff");
Pass::call(design, "proc_memwr");
Pass::call(design, "proc_clean");

View file

@ -345,7 +345,13 @@ struct proc_dlatch_db_t
}
};
void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
enum LatchPolicy {
POLICY_AUTO,
POLICY_WARN,
POLICY_ERROR
};
void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc, LatchPolicy policy)
{
RTLIL::SigSig latches_bits, nolatches_bits;
dict<SigBit, SigBit> latches_out_in;
@ -443,6 +449,12 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
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)
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)
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
log("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);
@ -458,22 +470,49 @@ struct ProcDlatchPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" proc_dlatch [selection]\n");
log(" proc_dlatch [options] [selection]\n");
log("\n");
log("This pass identifies latches in the processes and converts them to\n");
log("d-type latches.\n");
log("\n");
log(" -latches <auto|warn|error>\n");
log(" controls how the inference of a latch is reported. Alternatively, one\n");
log(" can use the 'proc.latches' scratchpad variable.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing PROC_DLATCH pass (convert process syncs to latches).\n");
extra_args(args, 1, design);
std::string policy_str;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-latches" && argidx+1 < args.size()) {
policy_str = args[++argidx];
continue;
}
break;
}
extra_args(args, argidx, design);
if (policy_str.empty())
policy_str = design->scratchpad_get_string("proc.latches", "warn");
LatchPolicy policy;
if (policy_str == "auto")
policy = POLICY_AUTO;
else if (policy_str == "warn")
policy = POLICY_WARN;
else if (policy_str == "error")
policy = POLICY_ERROR;
else
log_cmd_error("Invalid value '%s' for -latches (expected auto|warn|error).\n", policy_str.c_str());
for (auto mod : design->all_selected_modules()) {
proc_dlatch_db_t db(mod);
for (auto proc : mod->selected_processes())
proc_dlatch(db, proc);
proc_dlatch(db, proc, policy);
db.fixup_muxes();
}
}

View file

@ -78,6 +78,9 @@ struct SynthPass : public ScriptPass {
log(" -nordff\n");
log(" passed to 'memory'. prohibits merging of FFs into memory read ports\n");
log("\n");
log(" -latches <auto|warn|error>\n");
log(" controls how the inference of a latch is reported.\n");
log("\n");
log(" -noshare\n");
log(" do not run SAT-based resource sharing\n");
log("\n");
@ -111,7 +114,7 @@ struct SynthPass : public ScriptPass {
log("\n");
}
string top_module, fsm_opts, memory_opts, abc;
string top_module, fsm_opts, memory_opts, abc, latches_opt;
bool autotop, flatten, noalumacc, nofsm, noabc, noshare, flowmap, booth, arith_tree, hieropt, relative_share;
int lut;
std::vector<std::string> techmap_maps;
@ -121,6 +124,7 @@ struct SynthPass : public ScriptPass {
top_module.clear();
fsm_opts.clear();
memory_opts.clear();
latches_opt.clear();
autotop = false;
flatten = false;
@ -200,6 +204,10 @@ struct SynthPass : public ScriptPass {
memory_opts += " -nordff";
continue;
}
if (args[argidx] == "-latches" && argidx + 1 < args.size()) {
latches_opt += " -latches " + args[++argidx];
continue;
}
if (args[argidx] == "-noshare") {
noshare = true;
continue;
@ -276,7 +284,7 @@ struct SynthPass : public ScriptPass {
}
if (check_label("coarse")) {
run("proc");
run("proc" + latches_opt);
if (flatten || help_mode) {
run("check");
run("flatten", " (if -flatten)");

View file

@ -0,0 +1,32 @@
# warn
read_verilog <<EOT
module top(input g, rn, d, output reg q);
always @* if (~rn) q <= 0; else if (g) q <= d;
endmodule
EOT
logger -expect warning "Latch inferred for signal" 1
proc
logger -check-expected
design -reset
# auto
read_verilog <<EOT
module top(input g, rn, d, output reg q);
always @* if (~rn) q <= 0; else if (g) q <= d;
endmodule
EOT
logger -expect-no-warnings
proc -latches auto
logger -check-expected
design -reset
# error
read_verilog <<EOT
module top(input g, rn, d, output reg q);
always @* if (~rn) q <= 0; else if (g) q <= d;
endmodule
EOT
logger -expect error "Latch inferred for signal" 1
proc -latches error