Merge pull request #6036 from YosysHQ/nella/latch-diagnostics-2

`proc_dlatch`: error on implicit latches early [sc-645]
This commit is contained in:
nella
2026-09-22 15:33:40 +00:00
committed by GitHub
18 changed files with 183 additions and 115 deletions
+4 -1
View File
@@ -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 <info|warn|error>`` 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
+5 -5
View File
@@ -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_"))
) {
+1
View File
@@ -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
+1 -1
View File
@@ -69,7 +69,7 @@ struct ProcPass : public Pass {
log(" -noopt\n");
log(" Will omit the opt_expr pass.\n");
log("\n");
log(" -latches <auto|warn|error>\n");
log(" -latches <info|warn|error>\n");
log(" controls how the inference of a latch is reported.\n");
log("\n");
}
+12 -15
View File
@@ -22,6 +22,7 @@
#include "kernel/ffinit.h"
#include "kernel/consteval.h"
#include "kernel/log.h"
#include "passes/proc/proc_dlatch.h"
#include <sstream>
#include <stdlib.h>
#include <stdio.h>
@@ -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 <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(" 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<std::string> 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()) {
+67
View File
@@ -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<std::string> &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 <info|warn|error>\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
@@ -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)");
+1 -1
View File
@@ -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 <auto|warn|error>\n");
log(" -latches <info|warn|error>\n");
log(" controls how the inference of a latch is reported.\n");
log("\n");
log(" -noshare\n");
+8 -14
View File
@@ -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 <info|warn|error>\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<std::string> 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");
+8 -14
View File
@@ -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 <info|warn|error>\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<string> extra_plib, extra_map, extra_mlibmap;
std::vector<std::pair<string, string>> 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<std::string> 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");
}
+8 -14
View File
@@ -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 <info|warn|error>\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<std::string> 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>" : 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) {
+2 -1
View File
@@ -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");
+8 -15
View File
@@ -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 <info|warn|error>\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)");
}
+8 -15
View File
@@ -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 <info|warn|error>\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<std::string> 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");
+8 -15
View File
@@ -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 <info|warn|error>\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");
+14
View File
@@ -22,6 +22,20 @@ logger -check-expected
design -reset
# always_latch is exempt
read_verilog -sv <<EOT
module top(input g, d, output reg q);
always_latch if (g) q <= d;
endmodule
EOT
logger -expect-no-warnings
logger -expect log "Latch inferred for signal .* from always_latch process" 1
proc -latches error
logger -check-expected
select -assert-count 1 t:$dlatch a:always_latch %i
design -reset
# error
read_verilog <<EOT
module top(input g, rn, d, output reg q);
+12
View File
@@ -21,6 +21,18 @@ hierarchy -top top
proc
check -nolatches -assert
design -reset
read_verilog -sv <<EOT
module top(input g, d, output reg q);
always_latch if (g) q <= d;
endmodule
EOT
hierarchy -top top
proc
select -assert-count 1 t:$dlatch a:always_latch %i
check -nolatches -assert
check -latchonly -assert
design -reset
read_verilog <<EOT
module top(input g, d, output reg q, output y);
+14 -3
View File
@@ -14,7 +14,18 @@ design -load read
synth_ice40 -latches info
select -assert-count 1 t:SB_LUT4
design -load read
logger -expect warning "Latch inferred for signal" 1
logger -expect error "Found 1 problems in 'check -assert'" 1
# always_latch
design -reset
read_verilog -sv <<EOT
module top(input d, en, output reg q);
always_latch if (en) q = d;
endmodule
EOT
logger -expect-no-warnings
synth_ice40
logger -check-expected
select -assert-count 1 t:SB_LUT4
design -load read
logger -expect error "Latch inferred for signal" 1
synth_ice40