3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-07-02 13:36:08 +00:00
This commit is contained in:
nella 2026-06-18 16:05:20 +00:00 committed by GitHub
commit 16ed204d89
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 354 additions and 36 deletions

View file

@ -60,6 +60,11 @@ struct CheckPass : public Pass {
log(" also check for internal cells that have not been mapped to cells of the\n");
log(" target architecture\n");
log("\n");
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("\n");
log(" -allow-tbuf\n");
log(" modify the -mapped behavior to still allow $_TBUF_ cells\n");
log("\n");
@ -79,6 +84,7 @@ struct CheckPass : public Pass {
bool noinit = false;
bool initdrv = false;
bool mapped = false;
bool nolatches = false;
bool allow_tbuf = false;
bool assert_mode = false;
bool force_detailed_loop_check = false;
@ -98,6 +104,10 @@ struct CheckPass : public Pass {
mapped = true;
continue;
}
if (args[argidx] == "-nolatches") {
nolatches = true;
continue;
}
if (args[argidx] == "-allow-tbuf") {
allow_tbuf = true;
continue;
@ -114,12 +124,27 @@ struct CheckPass : public Pass {
}
extra_args(args, argidx, design);
bool latchonly = design->scratchpad_get_bool("check.latchonly", false);
log_header(design, "Executing CHECK pass (checking for obvious problems).\n");
for (auto module : design->selected_whole_modules_warn())
{
log("Checking module %s...\n", module);
// 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 (
cell->type.in(ID($dlatch), ID($adlatch), ID($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++;
}
continue;
}
SigMap sigmap(module);
dict<SigBit, vector<string>> wire_drivers;
dict<SigBit, Cell *> driver_cells;
@ -265,6 +290,15 @@ struct CheckPass : public Pass {
cell_allowed:;
}
if (
nolatches && (
cell->type.in(ID($dlatch), ID($adlatch), ID($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++;
}
for (auto &conn : cell->connections()) {
bool input = cell->input(conn.first);
bool output = cell->output(conn.first);

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_INFO,
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 <info|warn|error>\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("\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 == "info")
policy = POLICY_INFO;
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 info|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();
}
}