aboutsummaryrefslogtreecommitdiffstats
path: root/passes
diff options
context:
space:
mode:
Diffstat (limited to 'passes')
-rw-r--r--passes/cmds/add.cc4
-rw-r--r--passes/cmds/autoname.cc4
-rw-r--r--passes/cmds/blackbox.cc4
-rw-r--r--passes/cmds/bugpoint.cc10
-rw-r--r--passes/cmds/check.cc81
-rw-r--r--passes/cmds/chformal.cc4
-rw-r--r--passes/cmds/chtype.cc4
-rw-r--r--passes/cmds/connect.cc4
-rw-r--r--passes/cmds/connwrappers.cc4
-rw-r--r--passes/cmds/copy.cc4
-rw-r--r--passes/cmds/cover.cc4
-rw-r--r--passes/cmds/delete.cc4
-rw-r--r--passes/cmds/design.cc6
-rw-r--r--passes/cmds/edgetypes.cc4
-rw-r--r--passes/cmds/exec.cc4
-rw-r--r--passes/cmds/logcmd.cc4
-rw-r--r--passes/cmds/logger.cc4
-rw-r--r--passes/cmds/ltp.cc4
-rw-r--r--passes/cmds/plugin.cc4
-rw-r--r--passes/cmds/portlist.cc4
-rw-r--r--passes/cmds/printattrs.cc4
-rw-r--r--passes/cmds/qwp.cc4
-rw-r--r--passes/cmds/rename.cc8
-rw-r--r--passes/cmds/scatter.cc4
-rw-r--r--passes/cmds/scc.cc4
-rw-r--r--passes/cmds/scratchpad.cc4
-rw-r--r--passes/cmds/select.cc12
-rw-r--r--passes/cmds/setattr.cc16
-rw-r--r--passes/cmds/setundef.cc4
-rw-r--r--passes/cmds/show.cc10
-rw-r--r--passes/cmds/splice.cc6
-rw-r--r--passes/cmds/splitnets.cc39
-rw-r--r--passes/cmds/stat.cc11
-rw-r--r--passes/cmds/tee.cc4
-rw-r--r--passes/cmds/torder.cc4
-rw-r--r--passes/cmds/trace.cc20
-rw-r--r--passes/cmds/write_file.cc4
-rw-r--r--passes/equiv/equiv_add.cc4
-rw-r--r--passes/equiv/equiv_induct.cc8
-rw-r--r--passes/equiv/equiv_make.cc12
-rw-r--r--passes/equiv/equiv_mark.cc4
-rw-r--r--passes/equiv/equiv_miter.cc4
-rw-r--r--passes/equiv/equiv_opt.cc8
-rw-r--r--passes/equiv/equiv_purge.cc8
-rw-r--r--passes/equiv/equiv_remove.cc4
-rw-r--r--passes/equiv/equiv_simple.cc4
-rw-r--r--passes/equiv/equiv_status.cc4
-rw-r--r--passes/equiv/equiv_struct.cc4
-rw-r--r--passes/fsm/fsm.cc4
-rw-r--r--passes/fsm/fsm_detect.cc4
-rw-r--r--passes/fsm/fsm_expand.cc4
-rw-r--r--passes/fsm/fsm_export.cc4
-rw-r--r--passes/fsm/fsm_extract.cc4
-rw-r--r--passes/fsm/fsm_info.cc4
-rw-r--r--passes/fsm/fsm_map.cc4
-rw-r--r--passes/fsm/fsm_opt.cc4
-rw-r--r--passes/fsm/fsm_recode.cc4
-rw-r--r--passes/hierarchy/hierarchy.cc18
-rw-r--r--passes/hierarchy/submod.cc4
-rw-r--r--passes/hierarchy/uniquify.cc4
-rw-r--r--passes/memory/memory.cc4
-rw-r--r--passes/memory/memory_bram.cc215
-rw-r--r--passes/memory/memory_collect.cc236
-rw-r--r--passes/memory/memory_dff.cc148
-rw-r--r--passes/memory/memory_map.cc223
-rw-r--r--passes/memory/memory_memx.cc4
-rw-r--r--passes/memory/memory_nordff.cc76
-rw-r--r--passes/memory/memory_share.cc4
-rw-r--r--passes/memory/memory_unpack.cc120
-rw-r--r--passes/opt/Makefile.inc2
-rw-r--r--passes/opt/muxpack.cc4
-rw-r--r--passes/opt/opt.cc47
-rw-r--r--passes/opt/opt_clean.cc66
-rw-r--r--passes/opt/opt_demorgan.cc4
-rw-r--r--passes/opt/opt_dff.cc875
-rw-r--r--passes/opt/opt_expr.cc69
-rw-r--r--passes/opt/opt_lut.cc4
-rw-r--r--passes/opt/opt_lut_ins.cc4
-rw-r--r--passes/opt/opt_mem.cc91
-rw-r--r--passes/opt/opt_merge.cc12
-rw-r--r--passes/opt/opt_muxtree.cc4
-rw-r--r--passes/opt/opt_reduce.cc4
-rw-r--r--passes/opt/opt_rmdff.cc711
-rw-r--r--passes/opt/opt_share.cc365
-rw-r--r--passes/opt/pmux2shiftx.cc33
-rw-r--r--passes/opt/rmports.cc4
-rw-r--r--passes/opt/share.cc4
-rw-r--r--passes/opt/wreduce.cc72
-rw-r--r--passes/pmgen/Makefile.inc1
-rw-r--r--passes/pmgen/ice40_dsp.cc42
-rw-r--r--passes/pmgen/ice40_dsp.pmg295
-rw-r--r--passes/pmgen/ice40_wrapcarry.cc4
-rw-r--r--passes/pmgen/peepopt.cc7
-rw-r--r--passes/pmgen/peepopt_dffmux.pmg171
-rw-r--r--passes/pmgen/peepopt_muldiv.pmg5
-rw-r--r--passes/pmgen/peepopt_shiftmul.pmg6
-rw-r--r--passes/pmgen/pmgen.py20
-rw-r--r--passes/pmgen/test_pmgen.cc4
-rw-r--r--passes/pmgen/xilinx_dsp.cc163
-rw-r--r--passes/pmgen/xilinx_dsp.pmg333
-rw-r--r--passes/pmgen/xilinx_dsp48a.pmg322
-rw-r--r--passes/pmgen/xilinx_dsp_CREG.pmg122
-rw-r--r--passes/pmgen/xilinx_dsp_cascade.pmg125
-rw-r--r--passes/pmgen/xilinx_srl.cc4
-rw-r--r--passes/proc/proc.cc15
-rw-r--r--passes/proc/proc_arst.cc4
-rw-r--r--passes/proc/proc_clean.cc4
-rw-r--r--passes/proc/proc_dff.cc4
-rw-r--r--passes/proc/proc_dlatch.cc17
-rw-r--r--passes/proc/proc_init.cc4
-rw-r--r--passes/proc/proc_mux.cc4
-rw-r--r--passes/proc/proc_prune.cc4
-rw-r--r--passes/proc/proc_rmdead.cc4
-rw-r--r--passes/sat/assertpmux.cc4
-rw-r--r--passes/sat/async2sync.cc306
-rw-r--r--passes/sat/clk2fflogic.cc446
-rw-r--r--passes/sat/cutpoint.cc23
-rw-r--r--passes/sat/eval.cc4
-rw-r--r--passes/sat/expose.cc34
-rw-r--r--passes/sat/fmcombine.cc7
-rw-r--r--passes/sat/fminit.cc4
-rw-r--r--passes/sat/freduce.cc4
-rw-r--r--passes/sat/miter.cc4
-rw-r--r--passes/sat/mutate.cc10
-rw-r--r--passes/sat/qbfsat.cc439
-rw-r--r--passes/sat/qbfsat.h253
-rw-r--r--passes/sat/sat.cc14
-rw-r--r--passes/sat/sim.cc219
-rw-r--r--passes/sat/supercover.cc4
-rw-r--r--passes/techmap/Makefile.inc4
-rw-r--r--passes/techmap/abc.cc48
-rw-r--r--passes/techmap/abc9.cc14
-rw-r--r--passes/techmap/abc9_exe.cc17
-rw-r--r--passes/techmap/abc9_ops.cc8
-rw-r--r--passes/techmap/aigmap.cc4
-rw-r--r--passes/techmap/alumacc.cc4
-rw-r--r--passes/techmap/attrmap.cc16
-rw-r--r--passes/techmap/attrmvcp.cc4
-rw-r--r--passes/techmap/clkbufmap.cc62
-rw-r--r--passes/techmap/deminout.cc4
-rw-r--r--passes/techmap/dff2dffe.cc414
-rw-r--r--passes/techmap/dff2dffs.cc165
-rw-r--r--passes/techmap/dffinit.cc52
-rw-r--r--passes/techmap/dfflegalize.cc1323
-rw-r--r--passes/techmap/dfflibmap.cc293
-rw-r--r--passes/techmap/dffunmap.cc107
-rw-r--r--passes/techmap/extract.cc14
-rw-r--r--passes/techmap/extract_counter.cc14
-rw-r--r--passes/techmap/extract_fa.cc4
-rw-r--r--passes/techmap/extract_reduce.cc4
-rw-r--r--passes/techmap/extractinv.cc6
-rw-r--r--passes/techmap/flatten.cc11
-rw-r--r--passes/techmap/flowmap.cc4
-rw-r--r--passes/techmap/hilomap.cc4
-rw-r--r--passes/techmap/insbuf.cc4
-rw-r--r--passes/techmap/iopadmap.cc4
-rw-r--r--passes/techmap/lut2mux.cc4
-rw-r--r--passes/techmap/maccmap.cc4
-rw-r--r--passes/techmap/muxcover.cc4
-rw-r--r--passes/techmap/nlutmap.cc4
-rw-r--r--passes/techmap/pmuxtree.cc4
-rw-r--r--passes/techmap/shregmap.cc53
-rw-r--r--passes/techmap/simplemap.cc145
-rw-r--r--passes/techmap/techmap.cc131
-rw-r--r--passes/techmap/tribuf.cc4
-rw-r--r--passes/techmap/zinit.cc116
-rw-r--r--passes/tests/test_abcloop.cc10
-rw-r--r--passes/tests/test_autotb.cc4
-rw-r--r--passes/tests/test_cell.cc32
169 files changed, 5020 insertions, 5416 deletions
diff --git a/passes/cmds/add.cc b/passes/cmds/add.cc
index 91f8c2add..a2f4a9100 100644
--- a/passes/cmds/add.cc
+++ b/passes/cmds/add.cc
@@ -116,7 +116,7 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n
struct AddPass : public Pass {
AddPass() : Pass("add", "add objects to the design") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -150,7 +150,7 @@ struct AddPass : public Pass {
log("Add module[s] with the specified name[s].\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::string command;
std::string arg_name;
diff --git a/passes/cmds/autoname.cc b/passes/cmds/autoname.cc
index 50632201e..28d4012c4 100644
--- a/passes/cmds/autoname.cc
+++ b/passes/cmds/autoname.cc
@@ -92,7 +92,7 @@ int autoname_worker(Module *module)
struct AutonamePass : public Pass {
AutonamePass() : Pass("autoname", "automatically assign names to objects") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -102,7 +102,7 @@ struct AutonamePass : public Pass {
log("with $-prefix).\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/cmds/blackbox.cc b/passes/cmds/blackbox.cc
index b8297cd77..08a635514 100644
--- a/passes/cmds/blackbox.cc
+++ b/passes/cmds/blackbox.cc
@@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
struct BlackboxPass : public Pass {
BlackboxPass() : Pass("blackbox", "convert modules into blackbox modules") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -34,7 +34,7 @@ struct BlackboxPass : public Pass {
log("module attribute).\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/cmds/bugpoint.cc b/passes/cmds/bugpoint.cc
index 00aac596f..81d7a34bb 100644
--- a/passes/cmds/bugpoint.cc
+++ b/passes/cmds/bugpoint.cc
@@ -18,15 +18,15 @@
*/
#include "kernel/yosys.h"
-#include "backends/ilang/ilang_backend.h"
+#include "backends/rtlil/rtlil_backend.h"
USING_YOSYS_NAMESPACE
-using namespace ILANG_BACKEND;
+using namespace RTLIL_BACKEND;
PRIVATE_NAMESPACE_BEGIN
struct BugpointPass : public Pass {
BugpointPass() : Pass("bugpoint", "minimize testcases") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -90,7 +90,7 @@ struct BugpointPass : public Pass {
design->sort();
std::ofstream f("bugpoint-case.il");
- ILANG_BACKEND::dump_design(f, design, /*only_selected=*/false, /*flag_m=*/true, /*flag_n=*/false);
+ RTLIL_BACKEND::dump_design(f, design, /*only_selected=*/false, /*flag_m=*/true, /*flag_n=*/false);
f.close();
string yosys_cmdline = stringf("%s -qq -L bugpoint-case.log -s %s bugpoint-case.il", yosys_cmd.c_str(), script.c_str());
@@ -313,7 +313,7 @@ struct BugpointPass : public Pass {
return nullptr;
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
string yosys_cmd = "yosys", script, grep;
bool fast = false, clean = false;
diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc
index ba29e6f4b..36febb98a 100644
--- a/passes/cmds/check.cc
+++ b/passes/cmds/check.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct CheckPass : public Pass {
CheckPass() : Pass("check", "check for obvious problems in the design") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -35,33 +35,31 @@ struct CheckPass : public Pass {
log("\n");
log("This pass identifies the following problems in the current design:\n");
log("\n");
- log(" - combinatorial loops\n");
- log("\n");
- log(" - two or more conflicting drivers for one wire\n");
- log("\n");
- log(" - used wires that do not have a driver\n");
+ log(" - combinatorial loops\n");
+ log(" - two or more conflicting drivers for one wire\n");
+ log(" - used wires that do not have a driver\n");
log("\n");
log("Options:\n");
log("\n");
- log(" -noinit\n");
- log(" Also check for wires which have the 'init' attribute set.\n");
+ log(" -noinit\n");
+ log(" also check for wires which have the 'init' attribute set\n");
log("\n");
- log(" -initdrv\n");
- log(" Also check for wires that have the 'init' attribute set and are not\n");
- log(" driven by an FF cell type.\n");
+ log(" -initdrv\n");
+ log(" also check for wires that have the 'init' attribute set and are not\n");
+ log(" driven by an FF cell type\n");
log("\n");
- log(" -mapped\n");
- log(" Also check for internal cells that have not been mapped to cells of the\n");
- log(" target architecture.\n");
+ log(" -mapped\n");
+ log(" also check for internal cells that have not been mapped to cells of the\n");
+ log(" target architecture\n");
log("\n");
- log(" -allow-tbuf\n");
- log(" Modify the -mapped behavior to still allow $_TBUF_ cells.\n");
+ log(" -allow-tbuf\n");
+ log(" modify the -mapped behavior to still allow $_TBUF_ cells\n");
log("\n");
- log(" -assert\n");
- log(" Produce a runtime error if any problems are found in the current design.\n");
+ log(" -assert\n");
+ log(" produce a runtime error if any problems are found in the current design\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
int counter = 0;
bool noinit = false;
@@ -100,10 +98,7 @@ struct CheckPass : public Pass {
for (auto module : design->selected_whole_modules_warn())
{
- if (module->has_processes_warn())
- continue;
-
- log("checking module %s..\n", log_id(module));
+ log("Checking module %s...\n", log_id(module));
SigMap sigmap(module);
dict<SigBit, vector<string>> wire_drivers;
@@ -111,6 +106,44 @@ struct CheckPass : public Pass {
pool<SigBit> used_wires;
TopoSort<string> topo;
+ for (auto &proc_it : module->processes)
+ {
+ std::vector<RTLIL::CaseRule*> all_cases = {&proc_it.second->root_case};
+ for (size_t i = 0; i < all_cases.size(); i++) {
+ for (auto action : all_cases[i]->actions) {
+ for (auto bit : sigmap(action.first))
+ if (bit.wire) {
+ wire_drivers[bit].push_back(
+ stringf("action %s <= %s (case rule) in process %s",
+ log_signal(action.first), log_signal(action.second), log_id(proc_it.first)));
+ }
+ for (auto bit : sigmap(action.second))
+ if (bit.wire) used_wires.insert(bit);
+ }
+ for (auto switch_ : all_cases[i]->switches) {
+ for (auto case_ : switch_->cases) {
+ all_cases.push_back(case_);
+ for (auto compare : case_->compare)
+ for (auto bit : sigmap(compare))
+ if (bit.wire) used_wires.insert(bit);
+ }
+ }
+ }
+ for (auto &sync : proc_it.second->syncs) {
+ for (auto bit : sigmap(sync->signal))
+ if (bit.wire) used_wires.insert(bit);
+ for (auto action : sync->actions) {
+ for (auto bit : sigmap(action.first))
+ if (bit.wire)
+ wire_drivers[bit].push_back(
+ stringf("action %s <= %s (sync rule) in process %s",
+ log_signal(action.first), log_signal(action.second), log_id(proc_it.first)));
+ for (auto bit : sigmap(action.second))
+ if (bit.wire) used_wires.insert(bit);
+ }
+ }
+ }
+
for (auto cell : module->cells())
{
if (mapped && cell->type.begins_with("$") && design->module(cell->type) == nullptr) {
@@ -216,7 +249,7 @@ struct CheckPass : public Pass {
}
}
- log("found and reported %d problems.\n", counter);
+ log("Found and reported %d problems.\n", counter);
if (assert_mode && counter > 0)
log_error("Found %d problems in 'check -assert'.\n", counter);
diff --git a/passes/cmds/chformal.cc b/passes/cmds/chformal.cc
index d6e7f2ccf..a1b3fbef7 100644
--- a/passes/cmds/chformal.cc
+++ b/passes/cmds/chformal.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct ChformalPass : public Pass {
ChformalPass() : Pass("chformal", "change formal constraints of the design") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -62,7 +62,7 @@ struct ChformalPass : public Pass {
log(" change the roles of cells as indicated. these options can be combined\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool assert2assume = false;
bool assume2assert = false;
diff --git a/passes/cmds/chtype.cc b/passes/cmds/chtype.cc
index 979aeadd4..b894f334c 100644
--- a/passes/cmds/chtype.cc
+++ b/passes/cmds/chtype.cc
@@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
struct ChtypePass : public Pass {
ChtypePass() : Pass("chtype", "change type of cells in the design") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -40,7 +40,7 @@ struct ChtypePass : public Pass {
log("\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
IdString set_type;
dict<IdString, IdString> map_types;
diff --git a/passes/cmds/connect.cc b/passes/cmds/connect.cc
index 0b0868dfb..0cc6cbe52 100644
--- a/passes/cmds/connect.cc
+++ b/passes/cmds/connect.cc
@@ -43,7 +43,7 @@ static void unset_drivers(RTLIL::Design *design, RTLIL::Module *module, SigMap &
struct ConnectPass : public Pass {
ConnectPass() : Pass("connect", "create or remove connections") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -75,7 +75,7 @@ struct ConnectPass : public Pass {
log("This command does not operate on module with processes.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
RTLIL::Module *module = nullptr;
for (auto mod : design->selected_modules()) {
diff --git a/passes/cmds/connwrappers.cc b/passes/cmds/connwrappers.cc
index 6ae7c9304..9235dda2b 100644
--- a/passes/cmds/connwrappers.cc
+++ b/passes/cmds/connwrappers.cc
@@ -143,7 +143,7 @@ struct ConnwrappersWorker
struct ConnwrappersPass : public Pass {
ConnwrappersPass() : Pass("connwrappers", "match width of input-output port pairs") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -165,7 +165,7 @@ struct ConnwrappersPass : public Pass {
log("The options -signed, -unsigned, and -port can be specified multiple times.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
ConnwrappersWorker worker;
diff --git a/passes/cmds/copy.cc b/passes/cmds/copy.cc
index 99f1f69cf..c351065f3 100644
--- a/passes/cmds/copy.cc
+++ b/passes/cmds/copy.cc
@@ -26,7 +26,7 @@ PRIVATE_NAMESPACE_BEGIN
struct CopyPass : public Pass {
CopyPass() : Pass("copy", "copy modules in the design") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -36,7 +36,7 @@ struct CopyPass : public Pass {
log("by this command.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
if (args.size() != 3)
log_cmd_error("Invalid number of arguments!\n");
diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc
index 89d27c9aa..0867e3b4f 100644
--- a/passes/cmds/cover.cc
+++ b/passes/cmds/cover.cc
@@ -35,7 +35,7 @@ PRIVATE_NAMESPACE_BEGIN
struct CoverPass : public Pass {
CoverPass() : Pass("cover", "print code coverage counters") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -83,7 +83,7 @@ struct CoverPass : public Pass {
log("Coverage counters are only available in Yosys for Linux.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::vector<FILE*> out_files;
std::vector<std::string> patterns;
diff --git a/passes/cmds/delete.cc b/passes/cmds/delete.cc
index b124e3b0f..684fa37b0 100644
--- a/passes/cmds/delete.cc
+++ b/passes/cmds/delete.cc
@@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
struct DeletePass : public Pass {
DeletePass() : Pass("delete", "delete objects in the design") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -40,7 +40,7 @@ struct DeletePass : public Pass {
log("selected wires, thus 'deleting' module ports.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool flag_input = false;
bool flag_output = false;
diff --git a/passes/cmds/design.cc b/passes/cmds/design.cc
index 421defe0c..2d7ba1fef 100644
--- a/passes/cmds/design.cc
+++ b/passes/cmds/design.cc
@@ -28,7 +28,7 @@ std::vector<RTLIL::Design*> pushed_designs;
struct DesignPass : public Pass {
DesignPass() : Pass("design", "save, restore and reset current design") { }
- ~DesignPass() YS_OVERRIDE {
+ ~DesignPass() override {
for (auto &it : saved_designs)
delete it.second;
saved_designs.clear();
@@ -36,7 +36,7 @@ struct DesignPass : public Pass {
delete it;
pushed_designs.clear();
}
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -105,7 +105,7 @@ struct DesignPass : public Pass {
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool got_mode = false;
bool reset_mode = false;
diff --git a/passes/cmds/edgetypes.cc b/passes/cmds/edgetypes.cc
index 58ed6457d..37c420400 100644
--- a/passes/cmds/edgetypes.cc
+++ b/passes/cmds/edgetypes.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct EdgetypePass : public Pass {
EdgetypePass() : Pass("edgetypes", "list all types of edges in selection") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -35,7 +35,7 @@ struct EdgetypePass : public Pass {
log("is a 4-tuple of source and sink cell type and port name.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/cmds/exec.cc b/passes/cmds/exec.cc
index 7eeefe705..951fa53fc 100644
--- a/passes/cmds/exec.cc
+++ b/passes/cmds/exec.cc
@@ -38,7 +38,7 @@ PRIVATE_NAMESPACE_BEGIN
struct ExecPass : public Pass {
ExecPass() : Pass("exec", "execute commands in the operating system shell") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -71,7 +71,7 @@ struct ExecPass : public Pass {
log("\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::string cmd = "";
char buf[1024] = {};
diff --git a/passes/cmds/logcmd.cc b/passes/cmds/logcmd.cc
index 522e1089d..12c43ecec 100644
--- a/passes/cmds/logcmd.cc
+++ b/passes/cmds/logcmd.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct LogPass : public Pass {
LogPass() : Pass("log", "print text and log files") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -52,7 +52,7 @@ struct LogPass : public Pass {
log(" do not append a newline\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design*) override
{
size_t argidx;
bool to_stdout = false;
diff --git a/passes/cmds/logger.cc b/passes/cmds/logger.cc
index c9532eced..6a9ed6036 100644
--- a/passes/cmds/logger.cc
+++ b/passes/cmds/logger.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct LoggerPass : public Pass {
LoggerPass() : Pass("logger", "set logger properties") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -66,7 +66,7 @@ struct LoggerPass : public Pass {
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design * design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design * design) override
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/cmds/ltp.cc b/passes/cmds/ltp.cc
index 05701710b..39ec432c2 100644
--- a/passes/cmds/ltp.cc
+++ b/passes/cmds/ltp.cc
@@ -141,7 +141,7 @@ struct LtpWorker
struct LtpPass : public Pass {
LtpPass() : Pass("ltp", "print longest topological path") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -154,7 +154,7 @@ struct LtpPass : public Pass {
log(" automatically exclude FF cell types\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool noff = false;
diff --git a/passes/cmds/plugin.cc b/passes/cmds/plugin.cc
index 4c16b56c4..3ed19497d 100644
--- a/passes/cmds/plugin.cc
+++ b/passes/cmds/plugin.cc
@@ -99,7 +99,7 @@ void load_plugin(std::string, std::vector<std::string>)
struct PluginPass : public Pass {
PluginPass() : Pass("plugin", "load and list loaded plugins") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -117,7 +117,7 @@ struct PluginPass : public Pass {
log(" List loaded plugins\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::string plugin_filename;
std::vector<std::string> plugin_aliases;
diff --git a/passes/cmds/portlist.cc b/passes/cmds/portlist.cc
index 38c4a8597..97f4bfd99 100644
--- a/passes/cmds/portlist.cc
+++ b/passes/cmds/portlist.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct PortlistPass : public Pass {
PortlistPass() : Pass("portlist", "list (top-level) ports") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -39,7 +39,7 @@ struct PortlistPass : public Pass {
log(" print verilog blackbox module definitions instead of port lists\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool m_mode = false;
diff --git a/passes/cmds/printattrs.cc b/passes/cmds/printattrs.cc
index 80dbfa259..7973ac262 100644
--- a/passes/cmds/printattrs.cc
+++ b/passes/cmds/printattrs.cc
@@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
struct PrintAttrsPass : public Pass {
PrintAttrsPass() : Pass("printattrs", "print attributes of selected objects") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -48,7 +48,7 @@ struct PrintAttrsPass : public Pass {
log_assert(x.flags == RTLIL::CONST_FLAG_STRING || x.flags == RTLIL::CONST_FLAG_NONE); //intended to fail
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
size_t argidx = 1;
extra_args(args, argidx, design);
diff --git a/passes/cmds/qwp.cc b/passes/cmds/qwp.cc
index b178ef951..cf0f6d0de 100644
--- a/passes/cmds/qwp.cc
+++ b/passes/cmds/qwp.cc
@@ -778,7 +778,7 @@ struct QwpWorker
struct QwpPass : public Pass {
QwpPass() : Pass("qwp", "quadratic wirelength placer") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -808,7 +808,7 @@ struct QwpPass : public Pass {
log("dense matrix operations. It is only a toy-placer for small circuits.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
QwpConfig config;
xorshift32_state = 123456789;
diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc
index 7d6d84d42..f8fe715c8 100644
--- a/passes/cmds/rename.cc
+++ b/passes/cmds/rename.cc
@@ -104,7 +104,7 @@ static IdString derive_name_from_cell_output_wire(const RTLIL::Cell *cell)
struct RenamePass : public Pass {
RenamePass() : Pass("rename", "rename object in the design") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -152,7 +152,7 @@ struct RenamePass : public Pass {
log("Rename top module.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::string pattern_prefix = "_", pattern_suffix = "_";
bool flag_src = false;
@@ -290,11 +290,11 @@ struct RenamePass : public Pass {
dict<RTLIL::Cell *, IdString> new_cell_names;
for (auto wire : module->selected_wires())
- if (wire->name[0] == '\\' && wire->port_id == 0)
+ if (wire->name.isPublic() && wire->port_id == 0)
new_wire_names[wire] = NEW_ID;
for (auto cell : module->selected_cells())
- if (cell->name[0] == '\\')
+ if (cell->name.isPublic())
new_cell_names[cell] = NEW_ID;
for (auto &it : new_wire_names)
diff --git a/passes/cmds/scatter.cc b/passes/cmds/scatter.cc
index a5ef95f02..a70dd3086 100644
--- a/passes/cmds/scatter.cc
+++ b/passes/cmds/scatter.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct ScatterPass : public Pass {
ScatterPass() : Pass("scatter", "add additional intermediate nets") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -41,7 +41,7 @@ struct ScatterPass : public Pass {
log("Use the opt_clean command to get rid of the additional nets.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
CellTypes ct(design);
extra_args(args, 1, design);
diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc
index ad0554bae..8e7f3f990 100644
--- a/passes/cmds/scc.cc
+++ b/passes/cmds/scc.cc
@@ -218,7 +218,7 @@ struct SccWorker
struct SccPass : public Pass {
SccPass() : Pass("scc", "detect strongly connected components (logic loops)") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -255,7 +255,7 @@ struct SccPass : public Pass {
log(" that are part of a found logic loop\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::map<std::string, std::string> setAttr;
bool allCellTypes = false;
diff --git a/passes/cmds/scratchpad.cc b/passes/cmds/scratchpad.cc
index 34ec0863a..9369f5312 100644
--- a/passes/cmds/scratchpad.cc
+++ b/passes/cmds/scratchpad.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct ScratchpadPass : public Pass {
ScratchpadPass() : Pass("scratchpad", "get/set values in the scratchpad") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -63,7 +63,7 @@ struct ScratchpadPass : public Pass {
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc
index 13ee030a5..b4f3994a2 100644
--- a/passes/cmds/select.cc
+++ b/passes/cmds/select.cc
@@ -1021,7 +1021,7 @@ PRIVATE_NAMESPACE_BEGIN
struct SelectPass : public Pass {
SelectPass() : Pass("select", "modify and view the list of selected objects") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1250,7 +1250,7 @@ struct SelectPass : public Pass {
log(" select */t:SWITCH %%x:+[GATE] */t:SWITCH %%d\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool add_mode = false;
bool del_mode = false;
@@ -1587,7 +1587,7 @@ struct SelectPass : public Pass {
struct CdPass : public Pass {
CdPass() : Pass("cd", "a shortcut for 'select -module <name>'") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1613,7 +1613,7 @@ struct CdPass : public Pass {
log("This is just a shortcut for 'select -clear'.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
if (args.size() != 1 && args.size() != 2)
log_cmd_error("Invalid number of arguments.\n");
@@ -1693,7 +1693,7 @@ static void log_matches(const char *title, Module *module, const T &list)
struct LsPass : public Pass {
LsPass() : Pass("ls", "list modules or objects in modules") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1704,7 +1704,7 @@ struct LsPass : public Pass {
log("When an active module is selected, this prints a list of objects in the module.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
size_t argidx = 1;
extra_args(args, argidx, design);
diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc
index 515f5a4ef..3a94209d4 100644
--- a/passes/cmds/setattr.cc
+++ b/passes/cmds/setattr.cc
@@ -56,7 +56,7 @@ static void do_setunset(dict<RTLIL::IdString, RTLIL::Const> &attrs, const std::v
struct SetattrPass : public Pass {
SetattrPass() : Pass("setattr", "set/unset attributes on objects") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -69,7 +69,7 @@ struct SetattrPass : public Pass {
log("instead of objects within modules.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::vector<setunset_t> setunset_list;
bool flag_mod = false;
@@ -128,7 +128,7 @@ struct SetattrPass : public Pass {
struct WbflipPass : public Pass {
WbflipPass() : Pass("wbflip", "flip the whitebox attribute") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -138,7 +138,7 @@ struct WbflipPass : public Pass {
log("vice-versa. Blackbox cells are not effected by this command.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -167,7 +167,7 @@ struct WbflipPass : public Pass {
struct SetparamPass : public Pass {
SetparamPass() : Pass("setparam", "set/unset parameters on objects") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -179,7 +179,7 @@ struct SetparamPass : public Pass {
log("The -type option can be used to change the cell type of the selected cells.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
vector<setunset_t> setunset_list;
string new_cell_type;
@@ -219,7 +219,7 @@ struct SetparamPass : public Pass {
struct ChparamPass : public Pass {
ChparamPass() : Pass("chparam", "re-evaluate modules with new parameters") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -234,7 +234,7 @@ struct ChparamPass : public Pass {
log("List the available parameters of the selected modules.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::vector<setunset_t> setunset_list;
dict<RTLIL::IdString, RTLIL::Const> new_parameters;
diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc
index 8d973869e..cf8d76619 100644
--- a/passes/cmds/setundef.cc
+++ b/passes/cmds/setundef.cc
@@ -107,7 +107,7 @@ struct SetundefWorker
struct SetundefPass : public Pass {
SetundefPass() : Pass("setundef", "replace undef values with defined constants") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -147,7 +147,7 @@ struct SetundefPass : public Pass {
log(" replace undef in cell parameters\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
int got_value = 0;
bool undriven_mode = false;
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index fa922454a..0c96f8c5d 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -368,7 +368,7 @@ struct ShowWorker
const char *shape = "diamond";
if (wire->port_input || wire->port_output)
shape = "octagon";
- if (wire->name[0] == '\\') {
+ if (wire->name.isPublic()) {
fprintf(f, "n%d [ shape=%s, label=\"%s\", %s, fontcolor=\"black\" ];\n",
id2num(wire->name), shape, findLabel(wire->name.str()),
nextColor(RTLIL::SigSpec(wire), "color=\"black\"").c_str());
@@ -587,7 +587,7 @@ struct ShowWorker
struct ShowPass : public Pass {
ShowPass() : Pass("show", "generate schematics using graphviz") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -605,7 +605,7 @@ struct ShowPass : public Pass {
log(" generate a .dot file, or other <format> strings such as 'svg' or 'ps'\n");
log(" to generate files in other formats (this calls the 'dot' command).\n");
log("\n");
- log(" -lib <verilog_or_ilang_file>\n");
+ log(" -lib <verilog_or_rtlil_file>\n");
log(" Use the specified library file for determining whether cell ports are\n");
log(" inputs or outputs. This option can be used multiple times to specify\n");
log(" more than one library.\n");
@@ -674,7 +674,7 @@ struct ShowPass : public Pass {
log("the 'show' command is executed.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Generating Graphviz representation of design.\n");
log_push();
@@ -811,7 +811,7 @@ struct ShowPass : public Pass {
if (f.fail())
log_error("Can't open lib file `%s'.\n", filename.c_str());
RTLIL::Design *lib = new RTLIL::Design;
- Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0 ? "ilang" : "verilog"));
+ Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0 ? "rtlil" : "verilog"));
libs.push_back(lib);
}
diff --git a/passes/cmds/splice.cc b/passes/cmds/splice.cc
index ea9e06979..0f63b91c5 100644
--- a/passes/cmds/splice.cc
+++ b/passes/cmds/splice.cc
@@ -211,7 +211,7 @@ struct SpliceWorker
std::vector<Wire*> mod_wires = module->wires();
for (auto wire : mod_wires)
- if ((!no_outputs && wire->port_output) || (do_wires && wire->name[0] == '\\')) {
+ if ((!no_outputs && wire->port_output) || (do_wires && wire->name.isPublic())) {
if (!design->selected(module, wire))
continue;
RTLIL::SigSpec sig = sigmap(wire);
@@ -246,7 +246,7 @@ struct SpliceWorker
struct SplicePass : public Pass {
SplicePass() : Pass("splice", "create explicit splicing cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -287,7 +287,7 @@ struct SplicePass : public Pass {
log("by selected wires are rewired.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool sel_by_cell = false;
bool sel_by_wire = false;
diff --git a/passes/cmds/splitnets.cc b/passes/cmds/splitnets.cc
index 1e7dedd70..fff8a0d3e 100644
--- a/passes/cmds/splitnets.cc
+++ b/passes/cmds/splitnets.cc
@@ -59,18 +59,26 @@ struct SplitnetsWorker
new_wire->port_id = wire->port_id ? wire->port_id + offset : 0;
new_wire->port_input = wire->port_input;
new_wire->port_output = wire->port_output;
+ new_wire->start_offset = wire->start_offset + offset;
- if (wire->attributes.count(ID::src))
- new_wire->attributes[ID::src] = wire->attributes.at(ID::src);
+ auto it = wire->attributes.find(ID::src);
+ if (it != wire->attributes.end())
+ new_wire->attributes.emplace(ID::src, it->second);
- if (wire->attributes.count(ID::keep))
- new_wire->attributes[ID::keep] = wire->attributes.at(ID::keep);
+ it = wire->attributes.find(ID::hdlname);
+ if (it != wire->attributes.end())
+ new_wire->attributes.emplace(ID::hdlname, it->second);
- if (wire->attributes.count(ID::init)) {
- Const old_init = wire->attributes.at(ID::init), new_init;
+ it = wire->attributes.find(ID::keep);
+ if (it != wire->attributes.end())
+ new_wire->attributes.emplace(ID::keep, it->second);
+
+ it = wire->attributes.find(ID::init);
+ if (it != wire->attributes.end()) {
+ Const old_init = it->second, new_init;
for (int i = offset; i < offset+width; i++)
new_init.bits.push_back(i < GetSize(old_init) ? old_init.bits.at(i) : State::Sx);
- new_wire->attributes[ID::init] = new_init;
+ new_wire->attributes.emplace(ID::init, new_init);
}
std::vector<RTLIL::SigBit> sigvec = RTLIL::SigSpec(new_wire).to_sigbit_vector();
@@ -87,7 +95,7 @@ struct SplitnetsWorker
struct SplitnetsPass : public Pass {
SplitnetsPass() : Pass("splitnets", "split up multi-bit nets") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -109,7 +117,7 @@ struct SplitnetsPass : public Pass {
log(" and split nets so that no driver drives only part of a net.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool flag_ports = false;
bool flag_driver = false;
@@ -166,12 +174,12 @@ struct SplitnetsPass : public Pass {
std::map<RTLIL::Wire*, std::set<int>> split_wires_at;
- for (auto &c : module->cells_)
- for (auto &p : c.second->connections())
+ for (auto c : module->cells())
+ for (auto &p : c->connections())
{
- if (!ct.cell_known(c.second->type))
+ if (!ct.cell_known(c->type))
continue;
- if (!ct.cell_output(c.second->type, p.first))
+ if (!ct.cell_output(c->type, p.first))
continue;
RTLIL::SigSpec sig = p.second;
@@ -198,9 +206,8 @@ struct SplitnetsPass : public Pass {
}
else
{
- for (auto &w : module->wires_) {
- RTLIL::Wire *wire = w.second;
- if (wire->width > 1 && (wire->port_id == 0 || flag_ports) && design->selected(module, w.second))
+ for (auto wire : module->wires()) {
+ if (wire->width > 1 && (wire->port_id == 0 || flag_ports) && design->selected(module, wire))
worker.splitmap[wire] = std::vector<RTLIL::SigBit>();
}
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 30436d829..0d84c73db 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -81,7 +81,7 @@ struct statdata_t
for (auto wire : mod->selected_wires())
{
- if (wire->name[0] == '\\') {
+ if (wire->name.isPublic()) {
num_pub_wires++;
num_pub_wire_bits += wire->width;
}
@@ -117,7 +117,10 @@ struct statdata_t
}
else if (cell_type.in(ID($mux), ID($pmux)))
cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Y)));
- else if (cell_type.in(ID($sr), ID($dff), ID($dffsr), ID($adff), ID($dlatch), ID($dlatchsr)))
+ else if (cell_type.in(
+ ID($sr), ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre),
+ ID($adff), ID($adffe), ID($sdff), ID($sdffe), ID($sdffce),
+ ID($dlatch), ID($adlatch), ID($dlatchsr)))
cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Q)));
}
@@ -282,7 +285,7 @@ void read_liberty_cellarea(dict<IdString, double> &cell_area, string liberty_fil
struct StatPass : public Pass {
StatPass() : Pass("stat", "print some statistics") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -308,7 +311,7 @@ struct StatPass : public Pass {
log(" e.g. $add_8 for an 8 bit wide $add cell.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Printing statistics.\n");
diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc
index 1a44bdaec..60689fc82 100644
--- a/passes/cmds/tee.cc
+++ b/passes/cmds/tee.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct TeePass : public Pass {
TeePass() : Pass("tee", "redirect command output to file") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -49,7 +49,7 @@ struct TeePass : public Pass {
log(" Add/subtract INT from the -v setting for this command.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::vector<FILE*> backup_log_files, files_to_close;
std::vector<std::ostream*> backup_log_streams;
diff --git a/passes/cmds/torder.cc b/passes/cmds/torder.cc
index 5748ff7f0..30e76081e 100644
--- a/passes/cmds/torder.cc
+++ b/passes/cmds/torder.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct TorderPass : public Pass {
TorderPass() : Pass("torder", "print cells in topological order") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -43,7 +43,7 @@ struct TorderPass : public Pass {
log(" are not used in topological sorting. this option deactivates that.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool noautostop = false;
dict<IdString, pool<IdString>> stop_db;
diff --git a/passes/cmds/trace.cc b/passes/cmds/trace.cc
index 8446e27b3..10742c370 100644
--- a/passes/cmds/trace.cc
+++ b/passes/cmds/trace.cc
@@ -25,34 +25,34 @@ PRIVATE_NAMESPACE_BEGIN
struct TraceMonitor : public RTLIL::Monitor
{
- void notify_module_add(RTLIL::Module *module) YS_OVERRIDE
+ void notify_module_add(RTLIL::Module *module) override
{
log("#TRACE# Module add: %s\n", log_id(module));
}
- void notify_module_del(RTLIL::Module *module) YS_OVERRIDE
+ void notify_module_del(RTLIL::Module *module) override
{
log("#TRACE# Module delete: %s\n", log_id(module));
}
- void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, const RTLIL::SigSpec &sig) YS_OVERRIDE
+ void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, const RTLIL::SigSpec &sig) override
{
log("#TRACE# Cell connect: %s.%s.%s = %s (was: %s)\n", log_id(cell->module), log_id(cell), log_id(port), log_signal(sig), log_signal(old_sig));
}
- void notify_connect(RTLIL::Module *module, const RTLIL::SigSig &sigsig) YS_OVERRIDE
+ void notify_connect(RTLIL::Module *module, const RTLIL::SigSig &sigsig) override
{
log("#TRACE# Connection in module %s: %s = %s\n", log_id(module), log_signal(sigsig.first), log_signal(sigsig.second));
}
- void notify_connect(RTLIL::Module *module, const std::vector<RTLIL::SigSig> &sigsig_vec) YS_OVERRIDE
+ void notify_connect(RTLIL::Module *module, const std::vector<RTLIL::SigSig> &sigsig_vec) override
{
log("#TRACE# New connections in module %s:\n", log_id(module));
for (auto &sigsig : sigsig_vec)
log("## %s = %s\n", log_signal(sigsig.first), log_signal(sigsig.second));
}
- void notify_blackout(RTLIL::Module *module) YS_OVERRIDE
+ void notify_blackout(RTLIL::Module *module) override
{
log("#TRACE# Blackout in module %s:\n", log_id(module));
}
@@ -60,7 +60,7 @@ struct TraceMonitor : public RTLIL::Monitor
struct TracePass : public Pass {
TracePass() : Pass("trace", "redirect command output to file") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -70,7 +70,7 @@ struct TracePass : public Pass {
log("the design in real time.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -96,7 +96,7 @@ struct TracePass : public Pass {
struct DebugPass : public Pass {
DebugPass() : Pass("debug", "run command with debug log messages enabled") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -105,7 +105,7 @@ struct DebugPass : public Pass {
log("Execute the specified command with debug log messages enabled\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/cmds/write_file.cc b/passes/cmds/write_file.cc
index 64a762d7c..3d898a5ef 100644
--- a/passes/cmds/write_file.cc
+++ b/passes/cmds/write_file.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct WriteFileFrontend : public Frontend {
WriteFileFrontend() : Frontend("=write_file", "write a text to a file") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -44,7 +44,7 @@ struct WriteFileFrontend : public Frontend {
log(" EOT\n");
log("\n");
}
- void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
+ void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design*) override
{
bool append_mode = false;
std::string output_filename;
diff --git a/passes/equiv/equiv_add.cc b/passes/equiv/equiv_add.cc
index cdc74b0b2..2abbb59bb 100644
--- a/passes/equiv/equiv_add.cc
+++ b/passes/equiv/equiv_add.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct EquivAddPass : public Pass {
EquivAddPass() : Pass("equiv_add", "add a $equiv cell") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -39,7 +39,7 @@ struct EquivAddPass : public Pass {
log("This command adds $equiv cells for the ports of the specified cells.\n");
log("\n");
}
- void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, Design *design) override
{
bool try_mode = false;
diff --git a/passes/equiv/equiv_induct.cc b/passes/equiv/equiv_induct.cc
index ec651193e..37aec50cd 100644
--- a/passes/equiv/equiv_induct.cc
+++ b/passes/equiv/equiv_induct.cc
@@ -65,8 +65,10 @@ struct EquivInductWorker
int ez_a = satgen.importSigBit(bit_a, step);
int ez_b = satgen.importSigBit(bit_b, step);
int cond = ez->IFF(ez_a, ez_b);
- if (satgen.model_undef)
+ if (satgen.model_undef) {
+ cond = ez->AND(cond, ez->NOT(satgen.importUndefSigBit(bit_b, step)));
cond = ez->OR(cond, satgen.importUndefSigBit(bit_a, step));
+ }
ez_equal_terms.push_back(cond);
}
}
@@ -162,7 +164,7 @@ struct EquivInductWorker
struct EquivInductPass : public Pass {
EquivInductPass() : Pass("equiv_induct", "proving $equiv cells using temporal induction") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -192,7 +194,7 @@ struct EquivInductPass : public Pass {
log("after reset.\n");
log("\n");
}
- void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, Design *design) override
{
int success_counter = 0;
bool model_undef = false;
diff --git a/passes/equiv/equiv_make.cc b/passes/equiv/equiv_make.cc
index 50572ae5c..6923ae3d0 100644
--- a/passes/equiv/equiv_make.cc
+++ b/passes/equiv/equiv_make.cc
@@ -114,25 +114,25 @@ struct EquivMakeWorker
Module *gate_clone = gate_mod->clone();
for (auto it : gold_clone->wires().to_vector()) {
- if ((it->name[0] == '\\' || inames) && blacklist_names.count(it->name) == 0)
+ if ((it->name.isPublic() || inames) && blacklist_names.count(it->name) == 0)
wire_names.insert(it->name);
gold_clone->rename(it, it->name.str() + "_gold");
}
for (auto it : gold_clone->cells().to_vector()) {
- if ((it->name[0] == '\\' || inames) && blacklist_names.count(it->name) == 0)
+ if ((it->name.isPublic() || inames) && blacklist_names.count(it->name) == 0)
cell_names.insert(it->name);
gold_clone->rename(it, it->name.str() + "_gold");
}
for (auto it : gate_clone->wires().to_vector()) {
- if ((it->name[0] == '\\' || inames) && blacklist_names.count(it->name) == 0)
+ if ((it->name.isPublic() || inames) && blacklist_names.count(it->name) == 0)
wire_names.insert(it->name);
gate_clone->rename(it, it->name.str() + "_gate");
}
for (auto it : gate_clone->cells().to_vector()) {
- if ((it->name[0] == '\\' || inames) && blacklist_names.count(it->name) == 0)
+ if ((it->name.isPublic() || inames) && blacklist_names.count(it->name) == 0)
cell_names.insert(it->name);
gate_clone->rename(it, it->name.str() + "_gate");
}
@@ -466,7 +466,7 @@ struct EquivMakeWorker
struct EquivMakePass : public Pass {
EquivMakePass() : Pass("equiv_make", "prepare a circuit for equivalence checking") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -491,7 +491,7 @@ struct EquivMakePass : public Pass {
log("checking problem. Use 'miter -equiv' if you want to create a miter circuit.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
EquivMakeWorker worker;
worker.ct.setup(design);
diff --git a/passes/equiv/equiv_mark.cc b/passes/equiv/equiv_mark.cc
index 737de25d9..a722b5ed6 100644
--- a/passes/equiv/equiv_mark.cc
+++ b/passes/equiv/equiv_mark.cc
@@ -204,7 +204,7 @@ struct EquivMarkWorker
struct EquivMarkPass : public Pass {
EquivMarkPass() : Pass("equiv_mark", "mark equivalence checking regions") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -216,7 +216,7 @@ struct EquivMarkPass : public Pass {
log("wires and cells.\n");
log("\n");
}
- void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, Design *design) override
{
log_header(design, "Executing EQUIV_MARK pass.\n");
diff --git a/passes/equiv/equiv_miter.cc b/passes/equiv/equiv_miter.cc
index 085970189..e028f806a 100644
--- a/passes/equiv/equiv_miter.cc
+++ b/passes/equiv/equiv_miter.cc
@@ -261,7 +261,7 @@ struct EquivMiterWorker
struct EquivMiterPass : public Pass {
EquivMiterPass() : Pass("equiv_miter", "extract miter from equiv circuit") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -282,7 +282,7 @@ struct EquivMiterPass : public Pass {
log(" Create compare logic that handles undefs correctly\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
EquivMiterWorker worker;
worker.ct.setup(design);
diff --git a/passes/equiv/equiv_opt.cc b/passes/equiv/equiv_opt.cc
index 7c6c2e685..4d0400448 100644
--- a/passes/equiv/equiv_opt.cc
+++ b/passes/equiv/equiv_opt.cc
@@ -26,7 +26,7 @@ struct EquivOptPass:public ScriptPass
{
EquivOptPass() : ScriptPass("equiv_opt", "prove equivalence for optimized circuit") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -68,7 +68,7 @@ struct EquivOptPass:public ScriptPass
std::string command, techmap_opts, make_opts;
bool assert, undef, multiclock, async2sync;
- void clear_flags() YS_OVERRIDE
+ void clear_flags() override
{
command = "";
techmap_opts = "";
@@ -79,7 +79,7 @@ struct EquivOptPass:public ScriptPass
async2sync = false;
}
- void execute(std::vector < std::string > args, RTLIL::Design * design) YS_OVERRIDE
+ void execute(std::vector < std::string > args, RTLIL::Design * design) override
{
string run_from, run_to;
clear_flags();
@@ -148,7 +148,7 @@ struct EquivOptPass:public ScriptPass
log_pop();
}
- void script() YS_OVERRIDE
+ void script() override
{
if (check_label("run_pass")) {
run("hierarchy -auto-top");
diff --git a/passes/equiv/equiv_purge.cc b/passes/equiv/equiv_purge.cc
index 688c20f43..a43ecec5a 100644
--- a/passes/equiv/equiv_purge.cc
+++ b/passes/equiv/equiv_purge.cc
@@ -35,7 +35,7 @@ struct EquivPurgeWorker
{
if (sig.is_wire()) {
Wire *wire = sig.as_wire();
- if (wire->name[0] == '\\') {
+ if (wire->name.isPublic()) {
if (!wire->port_output) {
log(" Module output: %s (%s)\n", log_signal(wire), log_id(cellname));
wire->port_output = true;
@@ -62,7 +62,7 @@ struct EquivPurgeWorker
{
if (sig.is_wire()) {
Wire *wire = sig.as_wire();
- if (wire->name[0] == '\\') {
+ if (wire->name.isPublic()) {
if (!wire->port_output) {
log(" Module input: %s\n", log_signal(wire));
wire->port_input = true;
@@ -176,7 +176,7 @@ struct EquivPurgeWorker
struct EquivPurgePass : public Pass {
EquivPurgePass() : Pass("equiv_purge", "purge equivalence checking module") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -187,7 +187,7 @@ struct EquivPurgePass : public Pass {
log("ports as needed.\n");
log("\n");
}
- void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, Design *design) override
{
log_header(design, "Executing EQUIV_PURGE pass.\n");
diff --git a/passes/equiv/equiv_remove.cc b/passes/equiv/equiv_remove.cc
index 6daa112b5..89442308b 100644
--- a/passes/equiv/equiv_remove.cc
+++ b/passes/equiv/equiv_remove.cc
@@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
struct EquivRemovePass : public Pass {
EquivRemovePass() : Pass("equiv_remove", "remove $equiv cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -40,7 +40,7 @@ struct EquivRemovePass : public Pass {
log(" keep gate circuit\n");
log("\n");
}
- void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, Design *design) override
{
bool mode_gold = false;
bool mode_gate = false;
diff --git a/passes/equiv/equiv_simple.cc b/passes/equiv/equiv_simple.cc
index 4d2839f4d..408c5a793 100644
--- a/passes/equiv/equiv_simple.cc
+++ b/passes/equiv/equiv_simple.cc
@@ -273,7 +273,7 @@ struct EquivSimpleWorker
struct EquivSimplePass : public Pass {
EquivSimplePass() : Pass("equiv_simple", "try proving simple $equiv instances") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -298,7 +298,7 @@ struct EquivSimplePass : public Pass {
log(" the max. number of time steps to be considered (default = 1)\n");
log("\n");
}
- void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, Design *design) override
{
bool verbose = false, short_cones = false, model_undef = false, nogroup = false;
int success_counter = 0;
diff --git a/passes/equiv/equiv_status.cc b/passes/equiv/equiv_status.cc
index 258e2e45b..2db44ea90 100644
--- a/passes/equiv/equiv_status.cc
+++ b/passes/equiv/equiv_status.cc
@@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
struct EquivStatusPass : public Pass {
EquivStatusPass() : Pass("equiv_status", "print status of equivalent checking module") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -36,7 +36,7 @@ struct EquivStatusPass : public Pass {
log(" produce an error if any unproven $equiv cell is found\n");
log("\n");
}
- void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, Design *design) override
{
bool assert_mode = false;
int unproven_count = 0;
diff --git a/passes/equiv/equiv_struct.cc b/passes/equiv/equiv_struct.cc
index 1b7bf96a8..9784225db 100644
--- a/passes/equiv/equiv_struct.cc
+++ b/passes/equiv/equiv_struct.cc
@@ -283,7 +283,7 @@ struct EquivStructWorker
struct EquivStructPass : public Pass {
EquivStructPass() : Pass("equiv_struct", "structural equivalence checking") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -314,7 +314,7 @@ struct EquivStructPass : public Pass {
log(" maximum number of iterations to run before aborting\n");
log("\n");
}
- void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, Design *design) override
{
pool<IdString> fwonly_cells({ ID($equiv) });
bool mode_icells = false;
diff --git a/passes/fsm/fsm.cc b/passes/fsm/fsm.cc
index c5cb338ab..21d352407 100644
--- a/passes/fsm/fsm.cc
+++ b/passes/fsm/fsm.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct FsmPass : public Pass {
FsmPass() : Pass("fsm", "extract and optimize finite state machines") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -68,7 +68,7 @@ struct FsmPass : public Pass {
log(" passed through to fsm_recode pass\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool flag_nomap = false;
bool flag_norecode = false;
diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc
index 30e9e4dad..97c575ba7 100644
--- a/passes/fsm/fsm_detect.cc
+++ b/passes/fsm/fsm_detect.cc
@@ -257,7 +257,7 @@ static void detect_fsm(RTLIL::Wire *wire)
struct FsmDetectPass : public Pass {
FsmDetectPass() : Pass("fsm_detect", "finding FSMs in design") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -273,7 +273,7 @@ struct FsmDetectPass : public Pass {
log("'fsm_encoding' attribute to \"none\".\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing FSM_DETECT pass (finding FSMs in design).\n");
extra_args(args, 1, design);
diff --git a/passes/fsm/fsm_expand.cc b/passes/fsm/fsm_expand.cc
index ade6c17f5..d6b492af5 100644
--- a/passes/fsm/fsm_expand.cc
+++ b/passes/fsm/fsm_expand.cc
@@ -265,7 +265,7 @@ struct FsmExpand
struct FsmExpandPass : public Pass {
FsmExpandPass() : Pass("fsm_expand", "expand FSM cells by merging logic into it") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -279,7 +279,7 @@ struct FsmExpandPass : public Pass {
log("word-wide cells. Call with -full to consider all cells for merging.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool full_mode = false;
diff --git a/passes/fsm/fsm_export.cc b/passes/fsm/fsm_export.cc
index c02a54ea2..be6702d7e 100644
--- a/passes/fsm/fsm_export.cc
+++ b/passes/fsm/fsm_export.cc
@@ -120,7 +120,7 @@ void write_kiss2(struct RTLIL::Module *module, struct RTLIL::Cell *cell, std::st
*/
struct FsmExportPass : public Pass {
FsmExportPass() : Pass("fsm_export", "exporting FSMs to KISS2 files") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -143,7 +143,7 @@ struct FsmExportPass : public Pass {
log(" use binary state encoding as state names instead of s0, s1, ...\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
dict<RTLIL::IdString, RTLIL::Const>::iterator attr_it;
std::string arg;
diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc
index 6f99886f0..082973153 100644
--- a/passes/fsm/fsm_extract.cc
+++ b/passes/fsm/fsm_extract.cc
@@ -401,7 +401,7 @@ static void extract_fsm(RTLIL::Wire *wire)
struct FsmExtractPass : public Pass {
FsmExtractPass() : Pass("fsm_extract", "extracting FSMs in design") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -417,7 +417,7 @@ struct FsmExtractPass : public Pass {
log("'opt_clean' pass to eliminate this signal.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing FSM_EXTRACT pass (extracting FSM from design).\n");
extra_args(args, 1, design);
diff --git a/passes/fsm/fsm_info.cc b/passes/fsm/fsm_info.cc
index 90250f9b7..da0982bb9 100644
--- a/passes/fsm/fsm_info.cc
+++ b/passes/fsm/fsm_info.cc
@@ -30,7 +30,7 @@ PRIVATE_NAMESPACE_BEGIN
struct FsmInfoPass : public Pass {
FsmInfoPass() : Pass("fsm_info", "print information on finite state machines") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -41,7 +41,7 @@ struct FsmInfoPass : public Pass {
log("pass so that this information is included in the synthesis log file.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing FSM_INFO pass (dumping all available information on FSM cells).\n");
extra_args(args, 1, design);
diff --git a/passes/fsm/fsm_map.cc b/passes/fsm/fsm_map.cc
index 1765df092..a30d407f0 100644
--- a/passes/fsm/fsm_map.cc
+++ b/passes/fsm/fsm_map.cc
@@ -322,7 +322,7 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
struct FsmMapPass : public Pass {
FsmMapPass() : Pass("fsm_map", "mapping FSMs to basic logic") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -331,7 +331,7 @@ struct FsmMapPass : public Pass {
log("This pass translates FSM cells to flip-flops and logic.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing FSM_MAP pass (mapping FSMs to basic logic).\n");
extra_args(args, 1, design);
diff --git a/passes/fsm/fsm_opt.cc b/passes/fsm/fsm_opt.cc
index 89e8132d4..5fc1fb3bb 100644
--- a/passes/fsm/fsm_opt.cc
+++ b/passes/fsm/fsm_opt.cc
@@ -324,7 +324,7 @@ PRIVATE_NAMESPACE_BEGIN
struct FsmOptPass : public Pass {
FsmOptPass() : Pass("fsm_opt", "optimize finite state machines") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -335,7 +335,7 @@ struct FsmOptPass : public Pass {
log("combination with the 'opt_clean' pass (see also 'help fsm').\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing FSM_OPT pass (simple optimizations of FSMs).\n");
extra_args(args, 1, design);
diff --git a/passes/fsm/fsm_recode.cc b/passes/fsm/fsm_recode.cc
index 7edb923b9..d4a704270 100644
--- a/passes/fsm/fsm_recode.cc
+++ b/passes/fsm/fsm_recode.cc
@@ -126,7 +126,7 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs
struct FsmRecodePass : public Pass {
FsmRecodePass() : Pass("fsm_recode", "recoding finite state machines") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -151,7 +151,7 @@ struct FsmRecodePass : public Pass {
log(" .map <old_bitpattern> <new_bitpattern>\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
FILE *fm_set_fsm_file = NULL;
FILE *encfile = NULL;
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index b4eb0f1dd..225e1feae 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -224,7 +224,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
{
{".v", "verilog"},
{".sv", "verilog -sv"},
- {".il", "ilang"}
+ {".il", "rtlil"}
};
for (auto &ext : extensions_list)
@@ -558,7 +558,7 @@ RTLIL::Wire *find_implicit_port_wire(Module *module, Cell *cell, const std::stri
struct HierarchyPass : public Pass {
HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -639,7 +639,7 @@ struct HierarchyPass : public Pass {
log("in the current design.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing HIERARCHY pass (managing design hierarchy).\n");
@@ -765,11 +765,13 @@ struct HierarchyPass : public Pass {
top_mod = design->module(top_name);
dict<RTLIL::IdString, RTLIL::Const> top_parameters;
- for (auto &para : parameters) {
- SigSpec sig_value;
- if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second))
- log_cmd_error("Can't decode value '%s'!\n", para.second.c_str());
- top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const();
+ if ((top_mod == nullptr && design->module(abstract_id)) || top_mod != nullptr) {
+ for (auto &para : parameters) {
+ SigSpec sig_value;
+ if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second))
+ log_cmd_error("Can't decode value '%s'!\n", para.second.c_str());
+ top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const();
+ }
}
if (top_mod == nullptr && design->module(abstract_id))
diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc
index 2db7cf26b..b2826cbff 100644
--- a/passes/hierarchy/submod.cc
+++ b/passes/hierarchy/submod.cc
@@ -319,7 +319,7 @@ struct SubmodWorker
struct SubmodPass : public Pass {
SubmodPass() : Pass("submod", "moving part of a module to a new submodule") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -351,7 +351,7 @@ struct SubmodPass : public Pass {
log(" original module with original public names.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing SUBMOD pass (moving cells to submodules as requested).\n");
log_push();
diff --git a/passes/hierarchy/uniquify.cc b/passes/hierarchy/uniquify.cc
index 5dbd15a7e..3f9443a63 100644
--- a/passes/hierarchy/uniquify.cc
+++ b/passes/hierarchy/uniquify.cc
@@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
struct UniquifyPass : public Pass {
UniquifyPass() : Pass("uniquify", "create unique copies of modules") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -41,7 +41,7 @@ struct UniquifyPass : public Pass {
log("attribute set (the 'top' module is unique implicitly).\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing UNIQUIFY pass (creating unique copies of modules).\n");
diff --git a/passes/memory/memory.cc b/passes/memory/memory.cc
index cee63bdd8..282517992 100644
--- a/passes/memory/memory.cc
+++ b/passes/memory/memory.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct MemoryPass : public Pass {
MemoryPass() : Pass("memory", "translate memories to basic cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -49,7 +49,7 @@ struct MemoryPass : public Pass {
log("or multiport memory blocks if called with the -nomap option.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool flag_nomap = false;
bool flag_nordff = false;
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc
index 0898ec288..c6948fdba 100644
--- a/passes/memory/memory_bram.cc
+++ b/passes/memory/memory_bram.cc
@@ -18,6 +18,7 @@
*/
#include "kernel/yosys.h"
+#include "kernel/mem.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -400,9 +401,11 @@ struct rules_t
}
};
-bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram, const rules_t::match_t &match, dict<string, int> &match_properties, int mode)
+bool replace_memory(Mem &orig_mem, const rules_t &rules, const rules_t::bram_t &bram, const rules_t::match_t &match, dict<string, int> &match_properties, int mode)
{
- Module *module = cell->module;
+ // We will modify ports — make a copy of the structure.
+ Mem mem(orig_mem);
+ Module *module = mem.module;
auto portinfos = bram.make_portinfos();
int dup_count = 1;
@@ -437,46 +440,17 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
log(" Mapping to bram type %s (variant %d):\n", log_id(bram.name), bram.variant);
// bram.dump_config();
- int mem_size = cell->getParam(ID::SIZE).as_int();
- int mem_abits = cell->getParam(ID::ABITS).as_int();
- int mem_width = cell->getParam(ID::WIDTH).as_int();
- // int mem_offset = cell->getParam(ID::OFFSET).as_int();
-
- bool cell_init = !SigSpec(cell->getParam(ID::INIT)).is_fully_undef();
+ bool cell_init = !mem.inits.empty();
vector<Const> initdata;
if (cell_init) {
- Const initparam = cell->getParam(ID::INIT);
- initdata.reserve(mem_size);
- for (int i=0; i < mem_size; i++)
- initdata.push_back(initparam.extract(mem_width*i, mem_width, State::Sx));
+ Const initparam = mem.get_init_data();
+ initdata.reserve(mem.size);
+ for (int i=0; i < mem.size; i++)
+ initdata.push_back(initparam.extract(mem.width*i, mem.width, State::Sx));
}
- int wr_ports = cell->getParam(ID::WR_PORTS).as_int();
- auto wr_clken = SigSpec(cell->getParam(ID::WR_CLK_ENABLE));
- auto wr_clkpol = SigSpec(cell->getParam(ID::WR_CLK_POLARITY));
- wr_clken.extend_u0(wr_ports);
- wr_clkpol.extend_u0(wr_ports);
-
- SigSpec wr_en = cell->getPort(ID::WR_EN);
- SigSpec wr_clk = cell->getPort(ID::WR_CLK);
- SigSpec wr_data = cell->getPort(ID::WR_DATA);
- SigSpec wr_addr = cell->getPort(ID::WR_ADDR);
-
- int rd_ports = cell->getParam(ID::RD_PORTS).as_int();
- auto rd_clken = SigSpec(cell->getParam(ID::RD_CLK_ENABLE));
- auto rd_clkpol = SigSpec(cell->getParam(ID::RD_CLK_POLARITY));
- auto rd_transp = SigSpec(cell->getParam(ID::RD_TRANSPARENT));
- rd_clken.extend_u0(rd_ports);
- rd_clkpol.extend_u0(rd_ports);
- rd_transp.extend_u0(rd_ports);
-
- SigSpec rd_en = cell->getPort(ID::RD_EN);
- SigSpec rd_clk = cell->getPort(ID::RD_CLK);
- SigSpec rd_data = cell->getPort(ID::RD_DATA);
- SigSpec rd_addr = cell->getPort(ID::RD_ADDR);
-
- if (match.shuffle_enable && bram.dbits >= portinfos.at(match.shuffle_enable - 'A').enable*2 && portinfos.at(match.shuffle_enable - 'A').enable > 0 && wr_ports > 0)
+ if (match.shuffle_enable && bram.dbits >= portinfos.at(match.shuffle_enable - 'A').enable*2 && portinfos.at(match.shuffle_enable - 'A').enable > 0 && !mem.wr_ports.empty())
{
int bucket_size = bram.dbits / portinfos.at(match.shuffle_enable - 'A').enable;
log(" Shuffle bit order to accommodate enable buckets of size %d..\n", bucket_size);
@@ -487,23 +461,23 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
std::vector<SigSpec> old_wr_data;
std::vector<SigSpec> old_rd_data;
- for (int i = 0; i < wr_ports; i++) {
- old_wr_en.push_back(wr_en.extract(i*mem_width, mem_width));
- old_wr_data.push_back(wr_data.extract(i*mem_width, mem_width));
+ for (auto &port : mem.wr_ports) {
+ old_wr_en.push_back(port.en);
+ old_wr_data.push_back(port.data);
}
- for (int i = 0; i < rd_ports; i++)
- old_rd_data.push_back(rd_data.extract(i*mem_width, mem_width));
+ for (auto &port : mem.rd_ports)
+ old_rd_data.push_back(port.data);
// analyze enable structure
std::vector<SigSpec> en_order;
dict<SigSpec, vector<int>> bits_wr_en;
- for (int i = 0; i < mem_width; i++) {
+ for (int i = 0; i < mem.width; i++) {
SigSpec sig;
- for (int j = 0; j < wr_ports; j++)
- sig.append(old_wr_en[j][i]);
+ for (auto &port : mem.wr_ports)
+ sig.append(port.en[i]);
if (bits_wr_en.count(sig) == 0)
en_order.push_back(sig);
bits_wr_en[sig].push_back(i);
@@ -518,7 +492,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
std::vector<int> shuffle_map;
if (cell_init)
- new_initdata.resize(mem_size);
+ new_initdata.resize(mem.size);
for (auto &it : en_order)
{
@@ -528,29 +502,29 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
SigBit fillbit;
for (int i = 0; i < GetSize(bits); i++) {
- for (int j = 0; j < wr_ports; j++) {
+ for (int j = 0; j < GetSize(mem.wr_ports); j++) {
new_wr_en[j].append(old_wr_en[j][bits[i]]);
new_wr_data[j].append(old_wr_data[j][bits[i]]);
fillbit = old_wr_en[j][bits[i]];
}
- for (int j = 0; j < rd_ports; j++)
+ for (int j = 0; j < GetSize(mem.rd_ports); j++)
new_rd_data[j].append(old_rd_data[j][bits[i]]);
if (cell_init) {
- for (int j = 0; j < mem_size; j++)
+ for (int j = 0; j < mem.size; j++)
new_initdata[j].push_back(initdata[j][bits[i]]);
}
shuffle_map.push_back(bits[i]);
}
for (int i = 0; i < fillbits; i++) {
- for (int j = 0; j < wr_ports; j++) {
+ for (int j = 0; j < GetSize(mem.wr_ports); j++) {
new_wr_en[j].append(fillbit);
new_wr_data[j].append(State::S0);
}
- for (int j = 0; j < rd_ports; j++)
+ for (int j = 0; j < GetSize(mem.rd_ports); j++)
new_rd_data[j].append(State::Sx);
if (cell_init) {
- for (int j = 0; j < mem_size; j++)
+ for (int j = 0; j < mem.size; j++)
new_initdata[j].push_back(State::Sx);
}
shuffle_map.push_back(-1);
@@ -564,40 +538,38 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
// update mem_*, wr_*, and rd_* variables
- mem_width = GetSize(new_wr_en.front());
- wr_en = SigSpec(0, wr_ports * mem_width);
- wr_data = SigSpec(0, wr_ports * mem_width);
- rd_data = SigSpec(0, rd_ports * mem_width);
+ mem.width = GetSize(new_wr_en.front());
- for (int i = 0; i < wr_ports; i++) {
- wr_en.replace(i*mem_width, new_wr_en[i]);
- wr_data.replace(i*mem_width, new_wr_data[i]);
+ for (int i = 0; i < GetSize(mem.wr_ports); i++) {
+ auto &port = mem.wr_ports[i];
+ port.en = new_wr_en[i];
+ port.data = new_wr_data[i];
}
- for (int i = 0; i < rd_ports; i++)
- rd_data.replace(i*mem_width, new_rd_data[i]);
+ for (int i = 0; i < GetSize(mem.rd_ports); i++) {
+ auto &port = mem.rd_ports[i];
+ port.data = new_rd_data[i];
+ }
if (cell_init) {
- for (int i = 0; i < mem_size; i++)
+ for (int i = 0; i < mem.size; i++)
initdata[i] = Const(new_initdata[i]);
}
}
// assign write ports
pair<SigBit, bool> wr_clkdom;
- for (int cell_port_i = 0, bram_port_i = 0; cell_port_i < wr_ports; cell_port_i++)
+ for (int cell_port_i = 0, bram_port_i = 0; cell_port_i < GetSize(mem.wr_ports); cell_port_i++)
{
- bool clken = wr_clken[cell_port_i] == State::S1;
- bool clkpol = wr_clkpol[cell_port_i] == State::S1;
- SigBit clksig = wr_clk[cell_port_i];
+ auto &port = mem.wr_ports[cell_port_i];
- pair<SigBit, bool> clkdom(clksig, clkpol);
- if (!clken)
+ pair<SigBit, bool> clkdom(port.clk, port.clk_polarity);
+ if (!port.clk_enable)
clkdom = pair<SigBit, bool>(State::S1, false);
wr_clkdom = clkdom;
log(" Write port #%d is in clock domain %s%s.\n",
cell_port_i, clkdom.second ? "" : "!",
- clken ? log_signal(clkdom.first) : "~async~");
+ port.clk_enable ? log_signal(clkdom.first) : "~async~");
for (; bram_port_i < GetSize(portinfos); bram_port_i++)
{
@@ -609,7 +581,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
skip_bram_wport:
continue;
- if (clken) {
+ if (port.clk_enable) {
if (pi.clocks == 0) {
log(" Bram port %c%d has incompatible clock type.\n", pi.group + 'A', pi.index + 1);
goto skip_bram_wport;
@@ -618,7 +590,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
log(" Bram port %c%d is in a different clock domain.\n", pi.group + 'A', pi.index + 1);
goto skip_bram_wport;
}
- if (clock_polarities.count(pi.clkpol) && clock_polarities.at(pi.clkpol) != clkpol) {
+ if (clock_polarities.count(pi.clkpol) && clock_polarities.at(pi.clkpol) != port.clk_polarity) {
log(" Bram port %c%d has incompatible clock polarity.\n", pi.group + 'A', pi.index + 1);
goto skip_bram_wport;
}
@@ -631,12 +603,12 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
SigSpec sig_en;
SigBit last_en_bit = State::S1;
- for (int i = 0; i < mem_width; i++) {
+ for (int i = 0; i < mem.width; i++) {
if (pi.enable && i % (bram.dbits / pi.enable) == 0) {
- last_en_bit = wr_en[i + cell_port_i*mem_width];
+ last_en_bit = port.en[i];
sig_en.append(last_en_bit);
}
- if (last_en_bit != wr_en[i + cell_port_i*mem_width]) {
+ if (last_en_bit != port.en[i]) {
log(" Bram port %c%d has incompatible enable structure.\n", pi.group + 'A', pi.index + 1);
goto skip_bram_wport;
}
@@ -645,7 +617,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
log(" Mapped to bram port %c%d.\n", pi.group + 'A', pi.index + 1);
pi.mapped_port = cell_port_i;
- if (clken) {
+ if (port.clk_enable) {
clock_domains[pi.clocks] = clkdom;
clock_polarities[pi.clkpol] = clkdom.second;
pi.sig_clock = clkdom.first;
@@ -653,8 +625,8 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
}
pi.sig_en = sig_en;
- pi.sig_addr = wr_addr.extract(cell_port_i*mem_abits, mem_abits);
- pi.sig_data = wr_data.extract(cell_port_i*mem_width, mem_width);
+ pi.sig_addr = port.addr;
+ pi.sig_data = port.data;
bram_port_i++;
goto mapped_wr_port;
@@ -710,23 +682,21 @@ grow_read_ports:;
// assign read ports
- for (int cell_port_i = 0; cell_port_i < rd_ports; cell_port_i++)
+ for (int cell_port_i = 0; cell_port_i < GetSize(mem.rd_ports); cell_port_i++)
{
- bool clken = rd_clken[cell_port_i] == State::S1;
- bool clkpol = rd_clkpol[cell_port_i] == State::S1;
- bool transp = rd_transp[cell_port_i] == State::S1;
- SigBit clksig = rd_clk[cell_port_i];
+ auto &port = mem.rd_ports[cell_port_i];
+ bool transp = port.transparent;
- if (wr_ports == 0)
+ if (mem.wr_ports.empty())
transp = false;
- pair<SigBit, bool> clkdom(clksig, clkpol);
- if (!clken)
+ pair<SigBit, bool> clkdom(port.clk, port.clk_polarity);
+ if (!port.clk_enable)
clkdom = pair<SigBit, bool>(State::S1, false);
log(" Read port #%d is in clock domain %s%s.\n",
cell_port_i, clkdom.second ? "" : "!",
- clken ? log_signal(clkdom.first) : "~async~");
+ port.clk_enable ? log_signal(clkdom.first) : "~async~");
for (int bram_port_i = 0; bram_port_i < GetSize(portinfos); bram_port_i++)
{
@@ -736,7 +706,7 @@ grow_read_ports:;
skip_bram_rport:
continue;
- if (clken) {
+ if (port.clk_enable) {
if (pi.clocks == 0) {
if (match.make_outreg) {
pi.make_outreg = true;
@@ -749,20 +719,20 @@ grow_read_ports:;
log(" Bram port %c%d.%d is in a different clock domain.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
goto skip_bram_rport;
}
- if (clock_polarities.count(pi.clkpol) && clock_polarities.at(pi.clkpol) != clkpol) {
+ if (clock_polarities.count(pi.clkpol) && clock_polarities.at(pi.clkpol) != port.clk_polarity) {
log(" Bram port %c%d.%d has incompatible clock polarity.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
goto skip_bram_rport;
}
- if (rd_en[cell_port_i] != State::S1 && pi.enable == 0) {
+ if (port.en != State::S1 && pi.enable == 0) {
log(" Bram port %c%d.%d has no read enable input.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
goto skip_bram_rport;
}
skip_bram_rport_clkcheck:
if (read_transp.count(pi.transp) && read_transp.at(pi.transp) != transp) {
- if (match.make_transp && wr_ports <= 1) {
+ if (match.make_transp && GetSize(mem.wr_ports) <= 1) {
pi.make_transp = true;
if (pi.clocks != 0) {
- if (wr_ports == 1 && wr_clkdom != clkdom) {
+ if (GetSize(mem.wr_ports) == 1 && wr_clkdom != clkdom) {
log(" Bram port %c%d.%d cannot have soft transparency logic added as read and write clock domains differ.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
goto skip_bram_rport;
}
@@ -783,18 +753,18 @@ grow_read_ports:;
log(" Mapped to bram port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
pi.mapped_port = cell_port_i;
- if (clken) {
+ if (port.clk_enable) {
clock_domains[pi.clocks] = clkdom;
clock_polarities[pi.clkpol] = clkdom.second;
if (!pi.make_transp)
read_transp[pi.transp] = transp;
pi.sig_clock = clkdom.first;
- pi.sig_en = rd_en[cell_port_i];
+ pi.sig_en = port.en;
pi.effective_clkpol = clkdom.second;
}
- pi.sig_addr = rd_addr.extract(cell_port_i*mem_abits, mem_abits);
- pi.sig_data = rd_data.extract(cell_port_i*mem_width, mem_width);
+ pi.sig_addr = port.addr;
+ pi.sig_data = port.data;
if (grow_read_ports_cursor < cell_port_i) {
grow_read_ports_cursor = cell_port_i;
@@ -820,11 +790,11 @@ grow_read_ports:;
match_properties["dups"] = dup_count;
match_properties["waste"] = match_properties["dups"] * match_properties["bwaste"];
- int cells = ((mem_width + bram.dbits - 1) / bram.dbits) * ((mem_size + (1 << bram.abits) - 1) / (1 << bram.abits));
+ int cells = ((mem.width + bram.dbits - 1) / bram.dbits) * ((mem.size + (1 << bram.abits) - 1) / (1 << bram.abits));
match_properties["efficiency"] = (100 * match_properties["bits"]) / (dup_count * cells * bram.dbits * (1 << bram.abits));
- match_properties["dcells"] = ((mem_width + bram.dbits - 1) / bram.dbits);
- match_properties["acells"] = ((mem_size + (1 << bram.abits) - 1) / (1 << bram.abits));
+ match_properties["dcells"] = ((mem.width + bram.dbits - 1) / bram.dbits);
+ match_properties["acells"] = ((mem.size + (1 << bram.abits) - 1) / (1 << bram.abits));
match_properties["cells"] = match_properties["dcells"] * match_properties["acells"] * match_properties["dups"];
log(" Updated properties: dups=%d waste=%d efficiency=%d\n",
@@ -857,8 +827,8 @@ grow_read_ports:;
bool exists = std::get<0>(term);
IdString key = std::get<1>(term);
const Const &value = std::get<2>(term);
- auto it = cell->attributes.find(key);
- if (it == cell->attributes.end()) {
+ auto it = mem.attributes.find(key);
+ if (it == mem.attributes.end()) {
if (exists)
continue;
found = true;
@@ -902,7 +872,7 @@ grow_read_ports:;
dict<SigSpec, pair<SigSpec, SigSpec>> dout_cache;
- for (int grid_d = 0; grid_d*bram.dbits < mem_width; grid_d++)
+ for (int grid_d = 0; grid_d*bram.dbits < mem.width; grid_d++)
{
SigSpec mktr_wraddr, mktr_wrdata, mktr_wrdata_q;
vector<SigSpec> mktr_wren;
@@ -912,14 +882,14 @@ grow_read_ports:;
mktr_wrdata = module->addWire(NEW_ID, bram.dbits);
mktr_wrdata_q = module->addWire(NEW_ID, bram.dbits);
module->addDff(NEW_ID, make_transp_clk.first, mktr_wrdata, mktr_wrdata_q, make_transp_clk.second);
- for (int grid_a = 0; grid_a*(1 << bram.abits) < mem_size; grid_a++)
+ for (int grid_a = 0; grid_a*(1 << bram.abits) < mem.size; grid_a++)
mktr_wren.push_back(module->addWire(NEW_ID, make_transp_enbits));
}
- for (int grid_a = 0; grid_a*(1 << bram.abits) < mem_size; grid_a++)
+ for (int grid_a = 0; grid_a*(1 << bram.abits) < mem.size; grid_a++)
for (int dupidx = 0; dupidx < dup_count; dupidx++)
{
- Cell *c = module->addCell(module->uniquify(stringf("%s.%d.%d.%d", cell->name.c_str(), grid_d, grid_a, dupidx)), bram.name);
+ Cell *c = module->addCell(module->uniquify(stringf("%s.%d.%d.%d", mem.memid.c_str(), grid_d, grid_a, dupidx)), bram.name);
log(" Creating %s cell at grid position <%d %d %d>: %s\n", log_id(bram.name), grid_d, grid_a, dupidx, log_id(c));
for (auto &vp : variant_params)
@@ -1063,22 +1033,22 @@ grow_read_ports:;
}
}
- module->remove(cell);
+ mem.remove();
return true;
}
-void handle_cell(Cell *cell, const rules_t &rules)
+void handle_memory(Mem &mem, const rules_t &rules)
{
- log("Processing %s.%s:\n", log_id(cell->module), log_id(cell));
+ log("Processing %s.%s:\n", log_id(mem.module), log_id(mem.memid));
- bool cell_init = !SigSpec(cell->getParam(ID::INIT)).is_fully_undef();
+ bool cell_init = !mem.inits.empty();
dict<string, int> match_properties;
- match_properties["words"] = cell->getParam(ID::SIZE).as_int();
- match_properties["abits"] = cell->getParam(ID::ABITS).as_int();
- match_properties["dbits"] = cell->getParam(ID::WIDTH).as_int();
- match_properties["wports"] = cell->getParam(ID::WR_PORTS).as_int();
- match_properties["rports"] = cell->getParam(ID::RD_PORTS).as_int();
+ match_properties["words"] = mem.size;
+ match_properties["abits"] = ceil_log2(mem.size);
+ match_properties["dbits"] = mem.width;
+ match_properties["wports"] = GetSize(mem.wr_ports);
+ match_properties["rports"] = GetSize(mem.rd_ports);
match_properties["bits"] = match_properties["words"] * match_properties["dbits"];
match_properties["ports"] = match_properties["wports"] + match_properties["rports"];
@@ -1181,8 +1151,8 @@ void handle_cell(Cell *cell, const rules_t &rules)
bool exists = std::get<0>(term);
IdString key = std::get<1>(term);
const Const &value = std::get<2>(term);
- auto it = cell->attributes.find(key);
- if (it == cell->attributes.end()) {
+ auto it = mem.attributes.find(key);
+ if (it == mem.attributes.end()) {
if (exists)
continue;
found = true;
@@ -1219,7 +1189,7 @@ void handle_cell(Cell *cell, const rules_t &rules)
if (or_next_if_better && i+1 == GetSize(rules.matches) && vi+1 == GetSize(rules.brams.at(match.name)))
log_error("Found 'or_next_if_better' in last match rule.\n");
- if (!replace_cell(cell, rules, bram, match, match_properties, 1)) {
+ if (!replace_memory(mem, rules, bram, match, match_properties, 1)) {
log(" Mapping to bram type %s failed.\n", log_id(match.name));
failed_brams.insert(pair<IdString, int>(bram.name, bram.variant));
goto next_match_rule;
@@ -1246,12 +1216,12 @@ void handle_cell(Cell *cell, const rules_t &rules)
best_rule_cache.clear();
auto &best_bram = rules.brams.at(rules.matches.at(best_rule.first).name).at(best_rule.second);
- if (!replace_cell(cell, rules, best_bram, rules.matches.at(best_rule.first), match_properties, 2))
+ if (!replace_memory(mem, rules, best_bram, rules.matches.at(best_rule.first), match_properties, 2))
log_error("Mapping to bram type %s (variant %d) after pre-selection failed.\n", log_id(best_bram.name), best_bram.variant);
return;
}
- if (!replace_cell(cell, rules, bram, match, match_properties, 0)) {
+ if (!replace_memory(mem, rules, bram, match, match_properties, 0)) {
log(" Mapping to bram type %s failed.\n", log_id(match.name));
failed_brams.insert(pair<IdString, int>(bram.name, bram.variant));
goto next_match_rule;
@@ -1265,7 +1235,7 @@ void handle_cell(Cell *cell, const rules_t &rules)
struct MemoryBramPass : public Pass {
MemoryBramPass() : Pass("memory_bram", "map memories to block rams") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1367,7 +1337,7 @@ struct MemoryBramPass : public Pass {
log("the data bits to accommodate the enable pattern of port A.\n");
log("\n");
}
- void execute(vector<string> args, Design *design) YS_OVERRIDE
+ void execute(vector<string> args, Design *design) override
{
rules_t rules;
@@ -1384,9 +1354,8 @@ struct MemoryBramPass : public Pass {
extra_args(args, argidx, design);
for (auto mod : design->selected_modules())
- for (auto cell : mod->selected_cells())
- if (cell->type == ID($mem))
- handle_cell(cell, rules);
+ for (auto &mem : Mem::get_selected_memories(mod))
+ handle_memory(mem, rules);
}
} MemoryBramPass;
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc
index ef8b07811..ede6ca6a1 100644
--- a/passes/memory/memory_collect.cc
+++ b/passes/memory/memory_collect.cc
@@ -18,234 +18,14 @@
*/
#include "kernel/yosys.h"
-#include "kernel/sigtools.h"
+#include "kernel/mem.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-bool memcells_cmp(Cell *a, Cell *b)
-{
- if (a->type == ID($memrd) && b->type == ID($memrd))
- return a->name < b->name;
- if (a->type == ID($memrd) || b->type == ID($memrd))
- return (a->type == ID($memrd)) < (b->type == ID($memrd));
- return a->parameters.at(ID::PRIORITY).as_int() < b->parameters.at(ID::PRIORITY).as_int();
-}
-
-Cell *handle_memory(Module *module, RTLIL::Memory *memory)
-{
- log("Collecting $memrd, $memwr and $meminit for memory `%s' in module `%s':\n",
- memory->name.c_str(), module->name.c_str());
-
- Const init_data(State::Sx, memory->size * memory->width);
- SigMap sigmap(module);
-
- int wr_ports = 0;
- SigSpec sig_wr_clk;
- SigSpec sig_wr_clk_enable;
- SigSpec sig_wr_clk_polarity;
- SigSpec sig_wr_addr;
- SigSpec sig_wr_data;
- SigSpec sig_wr_en;
-
- int rd_ports = 0;
- SigSpec sig_rd_clk;
- SigSpec sig_rd_clk_enable;
- SigSpec sig_rd_clk_polarity;
- SigSpec sig_rd_transparent;
- SigSpec sig_rd_addr;
- SigSpec sig_rd_data;
- SigSpec sig_rd_en;
-
- int addr_bits = 0;
- std::vector<Cell*> memcells;
-
- for (auto cell : module->cells())
- if (cell->type.in(ID($memrd), ID($memwr), ID($meminit)) && memory->name == cell->parameters[ID::MEMID].decode_string()) {
- SigSpec addr = sigmap(cell->getPort(ID::ADDR));
- for (int i = 0; i < GetSize(addr); i++)
- if (addr[i] != State::S0)
- addr_bits = std::max(addr_bits, i+1);
- memcells.push_back(cell);
- }
-
- if (memory->start_offset == 0 && addr_bits < 30 && (1 << addr_bits) < memory->size)
- memory->size = 1 << addr_bits;
-
- if (memory->start_offset >= 0)
- addr_bits = std::min(addr_bits, ceil_log2(memory->size + memory->start_offset));
-
- addr_bits = std::max(addr_bits, 1);
-
- if (memcells.empty()) {
- log(" no cells found. removing memory.\n");
- return nullptr;
- }
-
- std::sort(memcells.begin(), memcells.end(), memcells_cmp);
-
- for (auto cell : memcells)
- {
- log(" %s (%s)\n", log_id(cell), log_id(cell->type));
-
- if (cell->type == ID($meminit))
- {
- SigSpec addr = sigmap(cell->getPort(ID::ADDR));
- SigSpec data = sigmap(cell->getPort(ID::DATA));
-
- if (!addr.is_fully_const())
- log_error("Non-constant address %s in memory initialization %s.\n", log_signal(addr), log_id(cell));
- if (!data.is_fully_const())
- log_error("Non-constant data %s in memory initialization %s.\n", log_signal(data), log_id(cell));
-
- int offset = (addr.as_int() - memory->start_offset) * memory->width;
-
- if (offset < 0 || offset + GetSize(data) > GetSize(init_data))
- log_warning("Address %s in memory initialization %s is out-of-bounds.\n", log_signal(addr), log_id(cell));
-
- for (int i = 0; i < GetSize(data); i++)
- if (0 <= i+offset && i+offset < GetSize(init_data))
- init_data.bits[i+offset] = data[i].data;
-
- continue;
- }
-
- if (cell->type == ID($memwr))
- {
- SigSpec clk = sigmap(cell->getPort(ID::CLK));
- SigSpec clk_enable = SigSpec(cell->parameters[ID::CLK_ENABLE]);
- SigSpec clk_polarity = SigSpec(cell->parameters[ID::CLK_POLARITY]);
- SigSpec addr = sigmap(cell->getPort(ID::ADDR));
- SigSpec data = sigmap(cell->getPort(ID::DATA));
- SigSpec en = sigmap(cell->getPort(ID::EN));
-
- if (!en.is_fully_zero())
- {
- clk.extend_u0(1, false);
- clk_enable.extend_u0(1, false);
- clk_polarity.extend_u0(1, false);
- addr.extend_u0(addr_bits, false);
- data.extend_u0(memory->width, false);
- en.extend_u0(memory->width, false);
-
- sig_wr_clk.append(clk);
- sig_wr_clk_enable.append(clk_enable);
- sig_wr_clk_polarity.append(clk_polarity);
- sig_wr_addr.append(addr);
- sig_wr_data.append(data);
- sig_wr_en.append(en);
-
- wr_ports++;
- }
- continue;
- }
-
- if (cell->type == ID($memrd))
- {
- SigSpec clk = sigmap(cell->getPort(ID::CLK));
- SigSpec clk_enable = SigSpec(cell->parameters[ID::CLK_ENABLE]);
- SigSpec clk_polarity = SigSpec(cell->parameters[ID::CLK_POLARITY]);
- SigSpec transparent = SigSpec(cell->parameters[ID::TRANSPARENT]);
- SigSpec addr = sigmap(cell->getPort(ID::ADDR));
- SigSpec data = sigmap(cell->getPort(ID::DATA));
- SigSpec en = sigmap(cell->getPort(ID::EN));
-
- if (!en.is_fully_zero())
- {
- clk.extend_u0(1, false);
- clk_enable.extend_u0(1, false);
- clk_polarity.extend_u0(1, false);
- transparent.extend_u0(1, false);
- addr.extend_u0(addr_bits, false);
- data.extend_u0(memory->width, false);
-
- sig_rd_clk.append(clk);
- sig_rd_clk_enable.append(clk_enable);
- sig_rd_clk_polarity.append(clk_polarity);
- sig_rd_transparent.append(transparent);
- sig_rd_addr.append(addr);
- sig_rd_data.append(data);
- sig_rd_en.append(en);
-
- rd_ports++;
- }
- continue;
- }
- }
-
- std::stringstream sstr;
- sstr << "$mem$" << memory->name.str() << "$" << (autoidx++);
-
- Cell *mem = module->addCell(sstr.str(), ID($mem));
- mem->parameters[ID::MEMID] = Const(memory->name.str());
- mem->parameters[ID::WIDTH] = Const(memory->width);
- mem->parameters[ID::OFFSET] = Const(memory->start_offset);
- mem->parameters[ID::SIZE] = Const(memory->size);
- mem->parameters[ID::ABITS] = Const(addr_bits);
- mem->parameters[ID::INIT] = init_data;
-
- log_assert(sig_wr_clk.size() == wr_ports);
- log_assert(sig_wr_clk_enable.size() == wr_ports && sig_wr_clk_enable.is_fully_const());
- log_assert(sig_wr_clk_polarity.size() == wr_ports && sig_wr_clk_polarity.is_fully_const());
- log_assert(sig_wr_addr.size() == wr_ports * addr_bits);
- log_assert(sig_wr_data.size() == wr_ports * memory->width);
- log_assert(sig_wr_en.size() == wr_ports * memory->width);
-
- mem->parameters[ID::WR_PORTS] = Const(wr_ports);
- mem->parameters[ID::WR_CLK_ENABLE] = wr_ports ? sig_wr_clk_enable.as_const() : State::S0;
- mem->parameters[ID::WR_CLK_POLARITY] = wr_ports ? sig_wr_clk_polarity.as_const() : State::S0;
-
- mem->setPort(ID::WR_CLK, sig_wr_clk);
- mem->setPort(ID::WR_ADDR, sig_wr_addr);
- mem->setPort(ID::WR_DATA, sig_wr_data);
- mem->setPort(ID::WR_EN, sig_wr_en);
-
- log_assert(sig_rd_clk.size() == rd_ports);
- log_assert(sig_rd_clk_enable.size() == rd_ports && sig_rd_clk_enable.is_fully_const());
- log_assert(sig_rd_clk_polarity.size() == rd_ports && sig_rd_clk_polarity.is_fully_const());
- log_assert(sig_rd_addr.size() == rd_ports * addr_bits);
- log_assert(sig_rd_data.size() == rd_ports * memory->width);
-
- mem->parameters[ID::RD_PORTS] = Const(rd_ports);
- mem->parameters[ID::RD_CLK_ENABLE] = rd_ports ? sig_rd_clk_enable.as_const() : State::S0;
- mem->parameters[ID::RD_CLK_POLARITY] = rd_ports ? sig_rd_clk_polarity.as_const() : State::S0;
- mem->parameters[ID::RD_TRANSPARENT] = rd_ports ? sig_rd_transparent.as_const() : State::S0;
-
- mem->setPort(ID::RD_CLK, sig_rd_clk);
- mem->setPort(ID::RD_ADDR, sig_rd_addr);
- mem->setPort(ID::RD_DATA, sig_rd_data);
- mem->setPort(ID::RD_EN, sig_rd_en);
-
- // Copy attributes from RTLIL memory to $mem
- for (auto attr : memory->attributes)
- mem->attributes[attr.first] = attr.second;
-
- for (auto c : memcells)
- module->remove(c);
-
- return mem;
-}
-
-static void handle_module(Design *design, Module *module)
-{
- std::vector<pair<Cell*, IdString>> finqueue;
-
- for (auto &mem_it : module->memories)
- if (design->selected(module, mem_it.second)) {
- Cell *c = handle_memory(module, mem_it.second);
- finqueue.push_back(pair<Cell*, IdString>(c, mem_it.first));
- }
- for (auto &it : finqueue) {
- delete module->memories.at(it.second);
- module->memories.erase(it.second);
- if (it.first)
- module->rename(it.first, it.second);
- }
-}
-
struct MemoryCollectPass : public Pass {
MemoryCollectPass() : Pass("memory_collect", "creating multi-port memory cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -255,11 +35,17 @@ struct MemoryCollectPass : public Pass {
log("memory cells.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override {
log_header(design, "Executing MEMORY_COLLECT pass (generating $mem cells).\n");
extra_args(args, 1, design);
- for (auto module : design->selected_modules())
- handle_module(design, module);
+ for (auto module : design->selected_modules()) {
+ for (auto &mem : Mem::get_selected_memories(module)) {
+ if (!mem.packed) {
+ mem.packed = true;
+ mem.emit();
+ }
+ }
+ }
}
} MemoryCollectPass;
diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc
index 726a5c1ff..4adcb462e 100644
--- a/passes/memory/memory_dff.cc
+++ b/passes/memory/memory_dff.cc
@@ -20,6 +20,7 @@
#include <algorithm>
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
+#include "kernel/ffinit.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -34,66 +35,158 @@ struct MemoryDffWorker
dict<SigBit, int> sigbit_users_count;
dict<SigSpec, Cell*> mux_cells_a, mux_cells_b;
pool<Cell*> forward_merged_dffs, candidate_dffs;
- pool<SigBit> init_bits;
+ FfInitVals initvals;
MemoryDffWorker(Module *module) : module(module), sigmap(module)
{
- for (auto wire : module->wires()) {
- if (wire->attributes.count(ID::init) == 0)
- continue;
- SigSpec sig = sigmap(wire);
- Const initval = wire->attributes.at(ID::init);
- for (int i = 0; i < GetSize(sig) && i < GetSize(initval); i++)
- if (initval[i] == State::S0 || initval[i] == State::S1)
- init_bits.insert(sig[i]);
- }
+ initvals.set(&sigmap, module);
}
- bool find_sig_before_dff(RTLIL::SigSpec &sig, RTLIL::SigSpec &clk, bool &clk_polarity, bool after = false)
+ bool find_sig_before_dff(RTLIL::SigSpec &sig, RTLIL::SigSpec &clk, bool &clk_polarity)
{
sigmap.apply(sig);
+ dict<SigBit, SigBit> cache;
+
for (auto &bit : sig)
{
+ if (cache.count(bit)) {
+ bit = cache[bit];
+ continue;
+ }
+
if (bit.wire == NULL)
continue;
- if (!after && init_bits.count(sigmap(bit)))
+ if (initvals(bit) != State::Sx)
return false;
for (auto cell : dff_cells)
{
- if (after && forward_merged_dffs.count(cell))
+ SigSpec this_clk = cell->getPort(ID::CLK);
+ bool this_clk_polarity = cell->parameters[ID::CLK_POLARITY].as_bool();
+
+ if (invbits.count(this_clk)) {
+ this_clk = invbits.at(this_clk);
+ this_clk_polarity = !this_clk_polarity;
+ }
+
+ if (clk != RTLIL::SigSpec(RTLIL::State::Sx)) {
+ if (this_clk != clk)
+ continue;
+ if (this_clk_polarity != clk_polarity)
+ continue;
+ }
+
+ RTLIL::SigSpec q_norm = cell->getPort(ID::Q);
+ sigmap.apply(q_norm);
+
+ RTLIL::SigSpec d = q_norm.extract(bit, &cell->getPort(ID::D));
+ if (d.size() != 1)
+ continue;
+
+ if (cell->type == ID($sdffce)) {
+ SigSpec rval = cell->parameters[ID::SRST_VALUE];
+ SigSpec rbit = q_norm.extract(bit, &rval);
+ if (cell->parameters[ID::SRST_POLARITY].as_bool())
+ d = module->Mux(NEW_ID, d, rbit, cell->getPort(ID::SRST));
+ else
+ d = module->Mux(NEW_ID, rbit, d, cell->getPort(ID::SRST));
+ }
+
+ if (cell->type.in(ID($dffe), ID($sdffe), ID($sdffce))) {
+ if (cell->parameters[ID::EN_POLARITY].as_bool())
+ d = module->Mux(NEW_ID, bit, d, cell->getPort(ID::EN));
+ else
+ d = module->Mux(NEW_ID, d, bit, cell->getPort(ID::EN));
+ }
+
+ if (cell->type.in(ID($sdff), ID($sdffe))) {
+ SigSpec rval = cell->parameters[ID::SRST_VALUE];
+ SigSpec rbit = q_norm.extract(bit, &rval);
+ if (cell->parameters[ID::SRST_POLARITY].as_bool())
+ d = module->Mux(NEW_ID, d, rbit, cell->getPort(ID::SRST));
+ else
+ d = module->Mux(NEW_ID, rbit, d, cell->getPort(ID::SRST));
+ }
+
+ cache[bit] = d;
+ bit = d;
+ clk = this_clk;
+ clk_polarity = this_clk_polarity;
+ candidate_dffs.insert(cell);
+ goto replaced_this_bit;
+ }
+
+ return false;
+ replaced_this_bit:;
+ }
+
+ return true;
+ }
+
+ bool find_sig_after_dffe(RTLIL::SigSpec &sig, RTLIL::SigSpec &clk, bool &clk_polarity, RTLIL::SigSpec &en, bool &en_polarity)
+ {
+ sigmap.apply(sig);
+
+ for (auto &bit : sig)
+ {
+ if (bit.wire == NULL)
+ continue;
+
+ for (auto cell : dff_cells)
+ {
+ if (forward_merged_dffs.count(cell))
+ continue;
+ if (!cell->type.in(ID($dff), ID($dffe)))
continue;
SigSpec this_clk = cell->getPort(ID::CLK);
bool this_clk_polarity = cell->parameters[ID::CLK_POLARITY].as_bool();
+ SigSpec this_en = State::S1;
+ bool this_en_polarity = true;
+
+ if (cell->type == ID($dffe)) {
+ this_en = cell->getPort(ID::EN);
+ this_en_polarity = cell->parameters[ID::EN_POLARITY].as_bool();
+ }
if (invbits.count(this_clk)) {
this_clk = invbits.at(this_clk);
this_clk_polarity = !this_clk_polarity;
}
+ if (invbits.count(this_en)) {
+ this_en = invbits.at(this_en);
+ this_en_polarity = !this_en_polarity;
+ }
+
if (clk != RTLIL::SigSpec(RTLIL::State::Sx)) {
if (this_clk != clk)
continue;
if (this_clk_polarity != clk_polarity)
continue;
+ if (this_en != en)
+ continue;
+ if (this_en_polarity != en_polarity)
+ continue;
}
- RTLIL::SigSpec q_norm = cell->getPort(after ? ID::D : ID::Q);
+ RTLIL::SigSpec q_norm = cell->getPort(ID::D);
sigmap.apply(q_norm);
- RTLIL::SigSpec d = q_norm.extract(bit, &cell->getPort(after ? ID::Q : ID::D));
+ RTLIL::SigSpec d = q_norm.extract(bit, &cell->getPort(ID::Q));
if (d.size() != 1)
continue;
- if (after && init_bits.count(d))
+ if (initvals(d) != State::Sx)
return false;
bit = d;
clk = this_clk;
clk_polarity = this_clk_polarity;
+ en = this_en;
+ en_polarity = this_en_polarity;
candidate_dffs.insert(cell);
goto replaced_this_bit;
}
@@ -161,7 +254,7 @@ struct MemoryDffWorker
RTLIL::SigSpec new_sig = module->addWire(sstr.str(), sig.size());
for (auto cell : module->cells())
- if (cell->type == ID($dff)) {
+ if (cell->type.in(ID($dff), ID($dffe))) {
RTLIL::SigSpec new_q = cell->getPort(ID::Q);
new_q.replace(sig, new_sig);
cell->setPort(ID::Q, new_q);
@@ -173,8 +266,10 @@ struct MemoryDffWorker
log("Checking cell `%s' in module `%s': ", cell->name.c_str(), module->name.c_str());
bool clk_polarity = 0;
+ bool en_polarity = 0;
RTLIL::SigSpec clk_data = RTLIL::SigSpec(RTLIL::State::Sx);
+ RTLIL::SigSpec en_data;
RTLIL::SigSpec sig_data = cell->getPort(ID::DATA);
for (auto bit : sigmap(sig_data))
@@ -198,9 +293,14 @@ struct MemoryDffWorker
if (sigbit_users_count[bit] > 1)
goto skip_ff_after_read_merging;
- if (find_sig_before_dff(sig_data, clk_data, clk_polarity, true) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx) &&
+ if (find_sig_after_dffe(sig_data, clk_data, clk_polarity, en_data, en_polarity) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx) &&
std::all_of(check_q.begin(), check_q.end(), [&](const SigSpec &cq) {return cq == sig_data; }))
{
+ if (en_data != State::S1 || !en_polarity) {
+ if (!en_polarity)
+ en_data = module->LogicNot(NEW_ID, en_data);
+ en.append(en_data);
+ }
disconnect_dff(sig_data);
cell->setPort(ID::CLK, clk_data);
cell->setPort(ID::EN, en.size() > 1 ? module->ReduceAnd(NEW_ID, en) : en);
@@ -214,11 +314,13 @@ struct MemoryDffWorker
}
else
{
- if (find_sig_before_dff(sig_data, clk_data, clk_polarity, true) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx))
+ if (find_sig_after_dffe(sig_data, clk_data, clk_polarity, en_data, en_polarity) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx))
{
+ if (!en_polarity)
+ en_data = module->LogicNot(NEW_ID, en_data);
disconnect_dff(sig_data);
cell->setPort(ID::CLK, clk_data);
- cell->setPort(ID::EN, State::S1);
+ cell->setPort(ID::EN, en_data);
cell->setPort(ID::DATA, sig_data);
cell->parameters[ID::CLK_ENABLE] = RTLIL::Const(1);
cell->parameters[ID::CLK_POLARITY] = RTLIL::Const(clk_polarity);
@@ -256,7 +358,7 @@ struct MemoryDffWorker
}
for (auto cell : module->cells()) {
- if (cell->type == ID($dff))
+ if (cell->type.in(ID($dff), ID($dffe), ID($sdff), ID($sdffe), ID($sdffce)))
dff_cells.push_back(cell);
if (cell->type == ID($mux)) {
mux_cells_a[sigmap(cell->getPort(ID::A))] = cell;
@@ -291,7 +393,7 @@ struct MemoryDffWorker
struct MemoryDffPass : public Pass {
MemoryDffPass() : Pass("memory_dff", "merge input/output DFFs into memories") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -305,7 +407,7 @@ struct MemoryDffPass : public Pass {
log(" do not merge registers on read ports\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool flag_wr_only = false;
diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc
index 9d455f55b..032b8fbbd 100644
--- a/passes/memory/memory_map.cc
+++ b/passes/memory/memory_map.cc
@@ -19,6 +19,7 @@
#include "kernel/register.h"
#include "kernel/log.h"
+#include "kernel/mem.h"
#include <sstream>
#include <set>
#include <stdlib.h>
@@ -97,35 +98,26 @@ struct MemoryMapWorker
return bit.wire;
}
- void handle_cell(RTLIL::Cell *cell)
+ void handle_memory(Mem &mem)
{
std::set<int> static_ports;
std::map<int, RTLIL::SigSpec> static_cells_map;
- int wr_ports = cell->parameters[ID::WR_PORTS].as_int();
- int rd_ports = cell->parameters[ID::RD_PORTS].as_int();
-
- int mem_size = cell->parameters[ID::SIZE].as_int();
- int mem_width = cell->parameters[ID::WIDTH].as_int();
- int mem_offset = cell->parameters[ID::OFFSET].as_int();
- int mem_abits = cell->parameters[ID::ABITS].as_int();
-
- SigSpec init_data = cell->getParam(ID::INIT);
- init_data.extend_u0(mem_size*mem_width, true);
+ SigSpec init_data = mem.get_init_data();
// delete unused memory cell
- if (wr_ports == 0 && rd_ports == 0) {
- module->remove(cell);
+ if (mem.rd_ports.empty()) {
+ mem.remove();
return;
}
- // check if attributes allow us to infer FFRAM for this cell
+ // check if attributes allow us to infer FFRAM for this memory
for (const auto &attr : attributes) {
- if (cell->attributes.count(attr.first)) {
- const auto &cell_attr = cell->attributes[attr.first];
+ if (mem.attributes.count(attr.first)) {
+ const auto &cell_attr = mem.attributes[attr.first];
if (attr.second.empty()) {
- log("Not mapping memory cell %s in module %s (attribute %s is set).\n",
- cell->name.c_str(), module->name.c_str(), attr.first.c_str());
+ log("Not mapping memory %s in module %s (attribute %s is set).\n",
+ mem.memid.c_str(), module->name.c_str(), attr.first.c_str());
return;
}
@@ -138,11 +130,11 @@ struct MemoryMapWorker
}
if (!found) {
if (cell_attr.flags & RTLIL::CONST_FLAG_STRING) {
- log("Not mapping memory cell %s in module %s (attribute %s is set to \"%s\").\n",
- cell->name.c_str(), module->name.c_str(), attr.first.c_str(), cell_attr.decode_string().c_str());
+ log("Not mapping memory %s in module %s (attribute %s is set to \"%s\").\n",
+ mem.memid.c_str(), module->name.c_str(), attr.first.c_str(), cell_attr.decode_string().c_str());
} else {
- log("Not mapping memory cell %s in module %s (attribute %s is set to %d).\n",
- cell->name.c_str(), module->name.c_str(), attr.first.c_str(), cell_attr.as_int());
+ log("Not mapping memory %s in module %s (attribute %s is set to %d).\n",
+ mem.memid.c_str(), module->name.c_str(), attr.first.c_str(), cell_attr.as_int());
}
return;
}
@@ -150,82 +142,75 @@ struct MemoryMapWorker
}
// all write ports must share the same clock
- RTLIL::SigSpec clocks = cell->getPort(ID::WR_CLK);
- RTLIL::Const clocks_pol = cell->parameters[ID::WR_CLK_POLARITY];
- RTLIL::Const clocks_en = cell->parameters[ID::WR_CLK_ENABLE];
- clocks_pol.bits.resize(wr_ports);
- clocks_en.bits.resize(wr_ports);
RTLIL::SigSpec refclock;
- RTLIL::State refclock_pol = RTLIL::State::Sx;
- for (int i = 0; i < clocks.size(); i++) {
- RTLIL::SigSpec wr_en = cell->getPort(ID::WR_EN).extract(i * mem_width, mem_width);
- if (wr_en.is_fully_const() && !wr_en.as_bool()) {
+ bool refclock_pol = false;
+ for (int i = 0; i < GetSize(mem.wr_ports); i++) {
+ auto &port = mem.wr_ports[i];
+ if (port.en.is_fully_const() && !port.en.as_bool()) {
static_ports.insert(i);
continue;
}
- if (clocks_en.bits[i] != RTLIL::State::S1) {
- RTLIL::SigSpec wr_addr = cell->getPort(ID::WR_ADDR).extract(i*mem_abits, mem_abits);
- RTLIL::SigSpec wr_data = cell->getPort(ID::WR_DATA).extract(i*mem_width, mem_width);
- if (wr_addr.is_fully_const()) {
- // FIXME: Actually we should check for wr_en.is_fully_const() also and
- // create a $adff cell with this ports wr_en input as reset pin when wr_en
+ if (!port.clk_enable) {
+ if (port.addr.is_fully_const()) {
+ // FIXME: Actually we should check for port.en.is_fully_const() also and
+ // create a $adff cell with this ports port.en input as reset pin when port.en
// is not a simple static 1.
- static_cells_map[wr_addr.as_int() - mem_offset] = wr_data;
+ static_cells_map[port.addr.as_int() - mem.start_offset] = port.data;
static_ports.insert(i);
continue;
}
- log("Not mapping memory cell %s in module %s (write port %d has no clock).\n",
- cell->name.c_str(), module->name.c_str(), i);
+ log("Not mapping memory %s in module %s (write port %d has no clock).\n",
+ mem.memid.c_str(), module->name.c_str(), i);
return;
}
if (refclock.size() == 0) {
- refclock = clocks.extract(i, 1);
- refclock_pol = clocks_pol.bits[i];
+ refclock = port.clk;
+ refclock_pol = port.clk_polarity;
}
- if (clocks.extract(i, 1) != refclock || clocks_pol.bits[i] != refclock_pol) {
- log("Not mapping memory cell %s in module %s (write clock %d is incompatible with other clocks).\n",
- cell->name.c_str(), module->name.c_str(), i);
+ if (port.clk != refclock || port.clk_polarity != refclock_pol) {
+ log("Not mapping memory %s in module %s (write clock %d is incompatible with other clocks).\n",
+ mem.memid.c_str(), module->name.c_str(), i);
return;
}
}
- log("Mapping memory cell %s in module %s:\n", cell->name.c_str(), module->name.c_str());
+ log("Mapping memory %s in module %s:\n", mem.memid.c_str(), module->name.c_str());
std::vector<RTLIL::SigSpec> data_reg_in;
std::vector<RTLIL::SigSpec> data_reg_out;
int count_static = 0;
- for (int i = 0; i < mem_size; i++)
+ for (int i = 0; i < mem.size; i++)
{
if (static_cells_map.count(i) > 0)
{
- data_reg_in.push_back(RTLIL::SigSpec(RTLIL::State::Sz, mem_width));
+ data_reg_in.push_back(RTLIL::SigSpec(RTLIL::State::Sz, mem.width));
data_reg_out.push_back(static_cells_map[i]);
count_static++;
}
else
{
- RTLIL::Cell *c = module->addCell(genid(cell->name, "", i), ID($dff));
- c->parameters[ID::WIDTH] = cell->parameters[ID::WIDTH];
- if (clocks_pol.bits.size() > 0) {
- c->parameters[ID::CLK_POLARITY] = RTLIL::Const(clocks_pol.bits[0]);
- c->setPort(ID::CLK, clocks.extract(0, 1));
+ RTLIL::Cell *c = module->addCell(genid(mem.memid, "", i), ID($dff));
+ c->parameters[ID::WIDTH] = mem.width;
+ if (GetSize(refclock) != 0) {
+ c->parameters[ID::CLK_POLARITY] = RTLIL::Const(refclock_pol);
+ c->setPort(ID::CLK, refclock);
} else {
c->parameters[ID::CLK_POLARITY] = RTLIL::Const(RTLIL::State::S1);
c->setPort(ID::CLK, RTLIL::SigSpec(RTLIL::State::S0));
}
- RTLIL::Wire *w_in = module->addWire(genid(cell->name, "", i, "$d"), mem_width);
+ RTLIL::Wire *w_in = module->addWire(genid(mem.memid, "", i, "$d"), mem.width);
data_reg_in.push_back(RTLIL::SigSpec(w_in));
c->setPort(ID::D, data_reg_in.back());
- std::string w_out_name = stringf("%s[%d]", cell->parameters[ID::MEMID].decode_string().c_str(), i);
+ std::string w_out_name = stringf("%s[%d]", mem.memid.c_str(), i);
if (module->wires_.count(w_out_name) > 0)
- w_out_name = genid(cell->name, "", i, "$q");
+ w_out_name = genid(mem.memid, "", i, "$q");
- RTLIL::Wire *w_out = module->addWire(w_out_name, mem_width);
- SigSpec w_init = init_data.extract(i*mem_width, mem_width);
+ RTLIL::Wire *w_out = module->addWire(w_out_name, mem.width);
+ SigSpec w_init = init_data.extract(i*mem.width, mem.width);
if (!w_init.is_fully_undef())
w_out->attributes[ID::init] = w_init.as_const();
@@ -235,76 +220,39 @@ struct MemoryMapWorker
}
}
- log(" created %d $dff cells and %d static cells of width %d.\n", mem_size-count_static, count_static, mem_width);
+ log(" created %d $dff cells and %d static cells of width %d.\n", mem.size-count_static, count_static, mem.width);
int count_dff = 0, count_mux = 0, count_wrmux = 0;
- for (int i = 0; i < cell->parameters[ID::RD_PORTS].as_int(); i++)
+ int abits = ceil_log2(mem.size);
+ for (int i = 0; i < GetSize(mem.rd_ports); i++)
{
- RTLIL::SigSpec rd_addr = cell->getPort(ID::RD_ADDR).extract(i*mem_abits, mem_abits);
+ auto &port = mem.rd_ports[i];
+ if (mem.extract_rdff(i))
+ count_dff++;
+ RTLIL::SigSpec rd_addr = port.addr;
+ rd_addr.extend_u0(abits, false);
- if (mem_offset)
- rd_addr = module->Sub(NEW_ID, rd_addr, SigSpec(mem_offset, GetSize(rd_addr)));
+ if (mem.start_offset)
+ rd_addr = module->Sub(NEW_ID, rd_addr, SigSpec(mem.start_offset, abits));
std::vector<RTLIL::SigSpec> rd_signals;
- rd_signals.push_back(cell->getPort(ID::RD_DATA).extract(i*mem_width, mem_width));
-
- if (cell->parameters[ID::RD_CLK_ENABLE].bits[i] == RTLIL::State::S1)
- {
- RTLIL::Cell *dff_cell = nullptr;
-
- if (cell->parameters[ID::RD_TRANSPARENT].bits[i] == RTLIL::State::S1)
- {
- dff_cell = module->addCell(genid(cell->name, "$rdreg", i), ID($dff));
- dff_cell->parameters[ID::WIDTH] = RTLIL::Const(mem_abits);
- dff_cell->parameters[ID::CLK_POLARITY] = RTLIL::Const(cell->parameters[ID::RD_CLK_POLARITY].bits[i]);
- dff_cell->setPort(ID::CLK, cell->getPort(ID::RD_CLK).extract(i, 1));
- dff_cell->setPort(ID::D, rd_addr);
- count_dff++;
-
- RTLIL::Wire *w = module->addWire(genid(cell->name, "$rdreg", i, "$q"), mem_abits);
-
- dff_cell->setPort(ID::Q, RTLIL::SigSpec(w));
- rd_addr = RTLIL::SigSpec(w);
- }
- else
- {
- dff_cell = module->addCell(genid(cell->name, "$rdreg", i), ID($dff));
- dff_cell->parameters[ID::WIDTH] = cell->parameters[ID::WIDTH];
- dff_cell->parameters[ID::CLK_POLARITY] = RTLIL::Const(cell->parameters[ID::RD_CLK_POLARITY].bits[i]);
- dff_cell->setPort(ID::CLK, cell->getPort(ID::RD_CLK).extract(i, 1));
- dff_cell->setPort(ID::Q, rd_signals.back());
- count_dff++;
-
- RTLIL::Wire *w = module->addWire(genid(cell->name, "$rdreg", i, "$d"), mem_width);
-
- rd_signals.clear();
- rd_signals.push_back(RTLIL::SigSpec(w));
- dff_cell->setPort(ID::D, rd_signals.back());
- }
-
- SigBit en_bit = cell->getPort(ID::RD_EN).extract(i);
- if (en_bit != State::S1) {
- SigSpec new_d = module->Mux(genid(cell->name, "$rdenmux", i),
- dff_cell->getPort(ID::Q), dff_cell->getPort(ID::D), en_bit);
- dff_cell->setPort(ID::D, new_d);
- }
- }
+ rd_signals.push_back(port.data);
- for (int j = 0; j < mem_abits; j++)
+ for (int j = 0; j < abits; j++)
{
std::vector<RTLIL::SigSpec> next_rd_signals;
for (size_t k = 0; k < rd_signals.size(); k++)
{
- RTLIL::Cell *c = module->addCell(genid(cell->name, "$rdmux", i, "", j, "", k), ID($mux));
- c->parameters[ID::WIDTH] = cell->parameters[ID::WIDTH];
+ RTLIL::Cell *c = module->addCell(genid(mem.memid, "$rdmux", i, "", j, "", k), ID($mux));
+ c->parameters[ID::WIDTH] = mem.width;
c->setPort(ID::Y, rd_signals[k]);
- c->setPort(ID::S, rd_addr.extract(mem_abits-j-1, 1));
+ c->setPort(ID::S, rd_addr.extract(abits-j-1, 1));
count_mux++;
- c->setPort(ID::A, module->addWire(genid(cell->name, "$rdmux", i, "", j, "", k, "$a"), mem_width));
- c->setPort(ID::B, module->addWire(genid(cell->name, "$rdmux", i, "", j, "", k, "$b"), mem_width));
+ c->setPort(ID::A, module->addWire(genid(mem.memid, "$rdmux", i, "", j, "", k, "$a"), mem.width));
+ c->setPort(ID::B, module->addWire(genid(mem.memid, "$rdmux", i, "", j, "", k, "$b"), mem.width));
next_rd_signals.push_back(c->getPort(ID::A));
next_rd_signals.push_back(c->getPort(ID::B));
@@ -313,38 +261,37 @@ struct MemoryMapWorker
next_rd_signals.swap(rd_signals);
}
- for (int j = 0; j < mem_size; j++)
+ for (int j = 0; j < mem.size; j++)
module->connect(RTLIL::SigSig(rd_signals[j], data_reg_out[j]));
}
log(" read interface: %d $dff and %d $mux cells.\n", count_dff, count_mux);
- for (int i = 0; i < mem_size; i++)
+ for (int i = 0; i < mem.size; i++)
{
if (static_cells_map.count(i) > 0)
continue;
RTLIL::SigSpec sig = data_reg_out[i];
- for (int j = 0; j < cell->parameters[ID::WR_PORTS].as_int(); j++)
+ for (int j = 0; j < GetSize(mem.wr_ports); j++)
{
- RTLIL::SigSpec wr_addr = cell->getPort(ID::WR_ADDR).extract(j*mem_abits, mem_abits);
- RTLIL::SigSpec wr_data = cell->getPort(ID::WR_DATA).extract(j*mem_width, mem_width);
- RTLIL::SigSpec wr_en = cell->getPort(ID::WR_EN).extract(j*mem_width, mem_width);
+ auto &port = mem.wr_ports[j];
+ RTLIL::SigSpec wr_addr = port.addr;
- if (mem_offset)
- wr_addr = module->Sub(NEW_ID, wr_addr, SigSpec(mem_offset, GetSize(wr_addr)));
+ if (mem.start_offset)
+ wr_addr = module->Sub(NEW_ID, wr_addr, SigSpec(mem.start_offset, GetSize(wr_addr)));
- RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(i, mem_abits));
+ RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(i, GetSize(wr_addr)));
int wr_offset = 0;
- while (wr_offset < wr_en.size())
+ while (wr_offset < port.en.size())
{
int wr_width = 1;
- RTLIL::SigSpec wr_bit = wr_en.extract(wr_offset, 1);
+ RTLIL::SigSpec wr_bit = port.en.extract(wr_offset, 1);
- while (wr_offset + wr_width < wr_en.size()) {
- RTLIL::SigSpec next_wr_bit = wr_en.extract(wr_offset + wr_width, 1);
+ while (wr_offset + wr_width < port.en.size()) {
+ RTLIL::SigSpec next_wr_bit = port.en.extract(wr_offset + wr_width, 1);
if (next_wr_bit != wr_bit)
break;
wr_width++;
@@ -354,7 +301,7 @@ struct MemoryMapWorker
if (wr_bit != State::S1)
{
- RTLIL::Cell *c = module->addCell(genid(cell->name, "$wren", i, "", j, "", wr_offset), ID($and));
+ RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wren", i, "", j, "", wr_offset), ID($and));
c->parameters[ID::A_SIGNED] = RTLIL::Const(0);
c->parameters[ID::B_SIGNED] = RTLIL::Const(0);
c->parameters[ID::A_WIDTH] = RTLIL::Const(1);
@@ -363,17 +310,17 @@ struct MemoryMapWorker
c->setPort(ID::A, w);
c->setPort(ID::B, wr_bit);
- w = module->addWire(genid(cell->name, "$wren", i, "", j, "", wr_offset, "$y"));
+ w = module->addWire(genid(mem.memid, "$wren", i, "", j, "", wr_offset, "$y"));
c->setPort(ID::Y, RTLIL::SigSpec(w));
}
- RTLIL::Cell *c = module->addCell(genid(cell->name, "$wrmux", i, "", j, "", wr_offset), ID($mux));
+ RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wrmux", i, "", j, "", wr_offset), ID($mux));
c->parameters[ID::WIDTH] = wr_width;
c->setPort(ID::A, sig.extract(wr_offset, wr_width));
- c->setPort(ID::B, wr_data.extract(wr_offset, wr_width));
+ c->setPort(ID::B, port.data.extract(wr_offset, wr_width));
c->setPort(ID::S, RTLIL::SigSpec(w));
- w = module->addWire(genid(cell->name, "$wrmux", i, "", j, "", wr_offset, "$y"), wr_width);
+ w = module->addWire(genid(mem.memid, "$wrmux", i, "", j, "", wr_offset, "$y"), wr_width);
c->setPort(ID::Y, w);
sig.replace(wr_offset, w);
@@ -387,23 +334,19 @@ struct MemoryMapWorker
log(" write interface: %d write mux blocks.\n", count_wrmux);
- module->remove(cell);
+ mem.remove();
}
void run()
{
- std::vector<RTLIL::Cell*> cells;
- for (auto cell : module->selected_cells())
- if (cell->type == ID($mem))
- cells.push_back(cell);
- for (auto cell : cells)
- handle_cell(cell);
+ for (auto &mem : Mem::get_selected_memories(module))
+ handle_memory(mem);
}
};
struct MemoryMapPass : public Pass {
MemoryMapPass() : Pass("memory_map", "translate multiport memories to basic cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -425,12 +368,12 @@ struct MemoryMapPass : public Pass {
log(" for -attr, ignore case of <value>.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool attr_icase = false;
dict<RTLIL::IdString, std::vector<RTLIL::Const>> attributes;
- log_header(design, "Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n");
+ log_header(design, "Executing MEMORY_MAP pass (converting memories to logic and flip-flops).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/memory/memory_memx.cc b/passes/memory/memory_memx.cc
index 5d5f61c7d..02e00cf30 100644
--- a/passes/memory/memory_memx.cc
+++ b/passes/memory/memory_memx.cc
@@ -28,7 +28,7 @@ PRIVATE_NAMESPACE_BEGIN
struct MemoryMemxPass : public Pass {
MemoryMemxPass() : Pass("memory_memx", "emulate vlog sim behavior for mem ports") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -38,7 +38,7 @@ struct MemoryMemxPass : public Pass {
log("behavior for out-of-bounds memory reads and writes.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override {
log_header(design, "Executing MEMORY_MEMX pass (converting $mem cells to logic and flip-flops).\n");
extra_args(args, 1, design);
diff --git a/passes/memory/memory_nordff.cc b/passes/memory/memory_nordff.cc
index 487785397..a4fdcfc38 100644
--- a/passes/memory/memory_nordff.cc
+++ b/passes/memory/memory_nordff.cc
@@ -19,13 +19,14 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
+#include "kernel/mem.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct MemoryNordffPass : public Pass {
MemoryNordffPass() : Pass("memory_nordff", "extract read port FFs from memories") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -35,9 +36,9 @@ struct MemoryNordffPass : public Pass {
log("similar to what one would get from calling memory_dff with -nordff.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
- log_header(design, "Executing MEMORY_NORDFF pass (extracting $dff cells from $mem).\n");
+ log_header(design, "Executing MEMORY_NORDFF pass (extracting $dff cells from memories).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
@@ -50,70 +51,15 @@ struct MemoryNordffPass : public Pass {
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
- for (auto cell : vector<Cell*>(module->selected_cells()))
+ for (auto &mem : Mem::get_selected_memories(module))
{
- if (cell->type != ID($mem))
- continue;
+ bool changed = false;
+ for (int i = 0; i < GetSize(mem.rd_ports); i++)
+ if (mem.extract_rdff(i))
+ changed = true;
- int rd_ports = cell->getParam(ID::RD_PORTS).as_int();
- int abits = cell->getParam(ID::ABITS).as_int();
- int width = cell->getParam(ID::WIDTH).as_int();
-
- SigSpec rd_addr = cell->getPort(ID::RD_ADDR);
- SigSpec rd_data = cell->getPort(ID::RD_DATA);
- SigSpec rd_clk = cell->getPort(ID::RD_CLK);
- SigSpec rd_en = cell->getPort(ID::RD_EN);
- Const rd_clk_enable = cell->getParam(ID::RD_CLK_ENABLE);
- Const rd_clk_polarity = cell->getParam(ID::RD_CLK_POLARITY);
-
- for (int i = 0; i < rd_ports; i++)
- {
- bool clk_enable = rd_clk_enable[i] == State::S1;
-
- if (clk_enable)
- {
- bool clk_polarity = cell->getParam(ID::RD_CLK_POLARITY)[i] == State::S1;
- bool transparent = cell->getParam(ID::RD_TRANSPARENT)[i] == State::S1;
-
- SigSpec clk = cell->getPort(ID::RD_CLK)[i] ;
- SigSpec en = cell->getPort(ID::RD_EN)[i];
- Cell *c;
-
- if (transparent)
- {
- SigSpec sig_q = module->addWire(NEW_ID, abits);
- SigSpec sig_d = rd_addr.extract(abits * i, abits);
- rd_addr.replace(abits * i, sig_q);
- if (en != State::S1)
- sig_d = module->Mux(NEW_ID, sig_q, sig_d, en);
- c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity);
- }
- else
- {
- SigSpec sig_d = module->addWire(NEW_ID, width);
- SigSpec sig_q = rd_data.extract(width * i, width);
- rd_data.replace(width *i, sig_d);
- if (en != State::S1)
- sig_d = module->Mux(NEW_ID, sig_q, sig_d, en);
- c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity);
- }
-
- log("Extracted %s FF from read port %d of %s.%s: %s\n", transparent ? "addr" : "data",
- i, log_id(module), log_id(cell), log_id(c));
- }
-
- rd_en[i] = State::S1;
- rd_clk[i] = State::S0;
- rd_clk_enable[i] = State::S0;
- rd_clk_polarity[i] = State::S1;
- }
-
- cell->setPort(ID::RD_ADDR, rd_addr);
- cell->setPort(ID::RD_DATA, rd_data);
- cell->setPort(ID::RD_CLK, rd_clk);
- cell->setPort(ID::RD_EN, rd_en);
- cell->setParam(ID::RD_CLK_ENABLE, rd_clk_enable);
- cell->setParam(ID::RD_CLK_POLARITY, rd_clk_polarity);
+ if (changed)
+ mem.emit();
}
}
} MemoryNordffPass;
diff --git a/passes/memory/memory_share.cc b/passes/memory/memory_share.cc
index e11958bd6..7315aeae1 100644
--- a/passes/memory/memory_share.cc
+++ b/passes/memory/memory_share.cc
@@ -734,7 +734,7 @@ struct MemoryShareWorker
struct MemorySharePass : public Pass {
MemorySharePass() : Pass("memory_share", "consolidate memory ports") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -760,7 +760,7 @@ struct MemorySharePass : public Pass {
log("optimizations) such as \"share\" and \"opt_merge\".\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override {
log_header(design, "Executing MEMORY_SHARE pass (consolidating $memrd/$memwr cells).\n");
extra_args(args, 1, design);
MemoryShareWorker msw(design);
diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc
index 8d284edcd..16b57d9c3 100644
--- a/passes/memory/memory_unpack.cc
+++ b/passes/memory/memory_unpack.cc
@@ -17,117 +17,15 @@
*
*/
-#include "kernel/register.h"
-#include "kernel/log.h"
-#include <sstream>
-#include <algorithm>
-#include <stdlib.h>
+#include "kernel/yosys.h"
+#include "kernel/mem.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
-{
- log("Creating $memrd and $memwr for memory `%s' in module `%s':\n",
- memory->name.c_str(), module->name.c_str());
-
- RTLIL::IdString mem_name = RTLIL::escape_id(memory->parameters.at(ID::MEMID).decode_string());
-
- while (module->memories.count(mem_name) != 0)
- mem_name = mem_name.str() + stringf("_%d", autoidx++);
-
- RTLIL::Memory *mem = new RTLIL::Memory;
- mem->name = mem_name;
- mem->width = memory->parameters.at(ID::WIDTH).as_int();
- mem->start_offset = memory->parameters.at(ID::OFFSET).as_int();
- mem->size = memory->parameters.at(ID::SIZE).as_int();
- module->memories[mem_name] = mem;
-
- int abits = memory->parameters.at(ID::ABITS).as_int();
- int num_rd_ports = memory->parameters.at(ID::RD_PORTS).as_int();
- int num_wr_ports = memory->parameters.at(ID::WR_PORTS).as_int();
-
- for (int i = 0; i < num_rd_ports; i++)
- {
- RTLIL::Cell *cell = module->addCell(NEW_ID, ID($memrd));
- cell->parameters[ID::MEMID] = mem_name.str();
- cell->parameters[ID::ABITS] = memory->parameters.at(ID::ABITS);
- cell->parameters[ID::WIDTH] = memory->parameters.at(ID::WIDTH);
- cell->parameters[ID::CLK_ENABLE] = RTLIL::SigSpec(memory->parameters.at(ID::RD_CLK_ENABLE)).extract(i, 1).as_const();
- cell->parameters[ID::CLK_POLARITY] = RTLIL::SigSpec(memory->parameters.at(ID::RD_CLK_POLARITY)).extract(i, 1).as_const();
- cell->parameters[ID::TRANSPARENT] = RTLIL::SigSpec(memory->parameters.at(ID::RD_TRANSPARENT)).extract(i, 1).as_const();
- cell->setPort(ID::CLK, memory->getPort(ID::RD_CLK).extract(i, 1));
- cell->setPort(ID::EN, memory->getPort(ID::RD_EN).extract(i, 1));
- cell->setPort(ID::ADDR, memory->getPort(ID::RD_ADDR).extract(i*abits, abits));
- cell->setPort(ID::DATA, memory->getPort(ID::RD_DATA).extract(i*mem->width, mem->width));
- }
-
- for (int i = 0; i < num_wr_ports; i++)
- {
- RTLIL::Cell *cell = module->addCell(NEW_ID, ID($memwr));
- cell->parameters[ID::MEMID] = mem_name.str();
- cell->parameters[ID::ABITS] = memory->parameters.at(ID::ABITS);
- cell->parameters[ID::WIDTH] = memory->parameters.at(ID::WIDTH);
- cell->parameters[ID::CLK_ENABLE] = RTLIL::SigSpec(memory->parameters.at(ID::WR_CLK_ENABLE)).extract(i, 1).as_const();
- cell->parameters[ID::CLK_POLARITY] = RTLIL::SigSpec(memory->parameters.at(ID::WR_CLK_POLARITY)).extract(i, 1).as_const();
- cell->parameters[ID::PRIORITY] = i;
- cell->setPort(ID::CLK, memory->getPort(ID::WR_CLK).extract(i, 1));
- cell->setPort(ID::EN, memory->getPort(ID::WR_EN).extract(i*mem->width, mem->width));
- cell->setPort(ID::ADDR, memory->getPort(ID::WR_ADDR).extract(i*abits, abits));
- cell->setPort(ID::DATA, memory->getPort(ID::WR_DATA).extract(i*mem->width, mem->width));
- }
-
- Const initval = memory->parameters.at(ID::INIT);
- RTLIL::Cell *last_init_cell = nullptr;
- SigSpec last_init_data;
- int last_init_addr=0;
-
- for (int i = 0; i < GetSize(initval) && i/mem->width < (1 << abits); i += mem->width) {
- Const val = initval.extract(i, mem->width, State::Sx);
- for (auto bit : val.bits)
- if (bit != State::Sx)
- goto found_non_undef_initval;
- continue;
- found_non_undef_initval:
- if (last_init_cell && last_init_addr+1 == i/mem->width) {
- last_init_cell->parameters[ID::WORDS] = last_init_cell->parameters[ID::WORDS].as_int() + 1;
- last_init_data.append(val);
- last_init_addr++;
- } else {
- if (last_init_cell)
- last_init_cell->setPort(ID::DATA, last_init_data);
- RTLIL::Cell *cell = module->addCell(NEW_ID, ID($meminit));
- cell->parameters[ID::MEMID] = mem_name.str();
- cell->parameters[ID::ABITS] = memory->parameters.at(ID::ABITS);
- cell->parameters[ID::WIDTH] = memory->parameters.at(ID::WIDTH);
- cell->parameters[ID::WORDS] = 1;
- cell->parameters[ID::PRIORITY] = i/mem->width;
- cell->setPort(ID::ADDR, SigSpec(i/mem->width, abits));
- last_init_cell = cell;
- last_init_addr = i/mem->width;
- last_init_data = val;
- }
- }
-
- if (last_init_cell)
- last_init_cell->setPort(ID::DATA, last_init_data);
-
- module->remove(memory);
-}
-
-void handle_module(RTLIL::Design *design, RTLIL::Module *module)
-{
- std::vector<RTLIL::IdString> memcells;
- for (auto cell : module->cells())
- if (cell->type == ID($mem) && design->selected(module, cell))
- memcells.push_back(cell->name);
- for (auto &it : memcells)
- handle_memory(module, module->cell(it));
-}
-
struct MemoryUnpackPass : public Pass {
MemoryUnpackPass() : Pass("memory_unpack", "unpack multi-port memory cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -137,11 +35,17 @@ struct MemoryUnpackPass : public Pass {
log("$memwr cells. It is the counterpart to the memory_collect pass.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override {
log_header(design, "Executing MEMORY_UNPACK pass (generating $memrd/$memwr cells form $mem cells).\n");
extra_args(args, 1, design);
- for (auto module : design->selected_modules())
- handle_module(design, module);
+ for (auto module : design->selected_modules()) {
+ for (auto &mem : Mem::get_selected_memories(module)) {
+ if (mem.packed) {
+ mem.packed = false;
+ mem.emit();
+ }
+ }
+ }
}
} MemoryUnpackPass;
diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc
index 3133927bb..4ae9b8895 100644
--- a/passes/opt/Makefile.inc
+++ b/passes/opt/Makefile.inc
@@ -4,7 +4,7 @@ OBJS += passes/opt/opt_merge.o
OBJS += passes/opt/opt_mem.o
OBJS += passes/opt/opt_muxtree.o
OBJS += passes/opt/opt_reduce.o
-OBJS += passes/opt/opt_rmdff.o
+OBJS += passes/opt/opt_dff.o
OBJS += passes/opt/opt_share.o
OBJS += passes/opt/opt_clean.o
OBJS += passes/opt/opt_expr.o
diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc
index 9df49ab3c..aa5f82437 100644
--- a/passes/opt/muxpack.cc
+++ b/passes/opt/muxpack.cc
@@ -326,7 +326,7 @@ struct MuxpackWorker
struct MuxpackPass : public Pass {
MuxpackPass() : Pass("muxpack", "$mux/$pmux cascades to $pmux") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -341,7 +341,7 @@ struct MuxpackPass : public Pass {
log("certain that their select inputs are mutually exclusive.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing MUXPACK pass ($mux cell cascades to $pmux).\n");
diff --git a/passes/opt/opt.cc b/passes/opt/opt.cc
index 396819883..4b052d9a2 100644
--- a/passes/opt/opt.cc
+++ b/passes/opt/opt.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct OptPass : public Pass {
OptPass() : Pass("opt", "perform simple optimizations") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -37,42 +37,43 @@ struct OptPass : public Pass {
log("a series of trivial optimizations and cleanups. This pass executes the other\n");
log("passes in the following order:\n");
log("\n");
- log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
+ log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-noclkinv] [-fine] [-full] [-keepdc]\n");
log(" opt_merge [-share_all] -nomux\n");
log("\n");
log(" do\n");
log(" opt_muxtree\n");
log(" opt_reduce [-fine] [-full]\n");
log(" opt_merge [-share_all]\n");
- log(" opt_share (-full only)\n");
- log(" opt_rmdff [-keepdc] [-sat]\n");
+ log(" opt_share (-full only)\n");
+ log(" opt_dff [-nodffe] [-nosdff] [-keepdc] [-sat] (except when called with -noff)\n");
log(" opt_clean [-purge]\n");
- log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
+ log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-noclkinv] [-fine] [-full] [-keepdc]\n");
log(" while <changed design>\n");
log("\n");
log("When called with -fast the following script is used instead:\n");
log("\n");
log(" do\n");
- log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
+ log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-noclkinv] [-fine] [-full] [-keepdc]\n");
log(" opt_merge [-share_all]\n");
- log(" opt_rmdff [-keepdc] [-sat]\n");
+ log(" opt_dff [-nodffe] [-nosdff] [-keepdc] [-sat] (except when called with -noff)\n");
log(" opt_clean [-purge]\n");
- log(" while <changed design in opt_rmdff>\n");
+ log(" while <changed design in opt_dff>\n");
log("\n");
log("Note: Options in square brackets (such as [-keepdc]) are passed through to\n");
log("the opt_* commands when given to 'opt'.\n");
log("\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::string opt_clean_args;
std::string opt_expr_args;
std::string opt_reduce_args;
std::string opt_merge_args;
- std::string opt_rmdff_args;
+ std::string opt_dff_args;
bool opt_share = false;
bool fast_mode = false;
+ bool noff_mode = false;
log_header(design, "Executing OPT pass (performing simple optimizations).\n");
log_push();
@@ -95,8 +96,8 @@ struct OptPass : public Pass {
opt_expr_args += " -undriven";
continue;
}
- if (args[argidx] == "-clkinv") {
- opt_expr_args += " -clkinv";
+ if (args[argidx] == "-noclkinv") {
+ opt_expr_args += " -noclkinv";
continue;
}
if (args[argidx] == "-fine") {
@@ -112,11 +113,19 @@ struct OptPass : public Pass {
}
if (args[argidx] == "-keepdc") {
opt_expr_args += " -keepdc";
- opt_rmdff_args += " -keepdc";
+ opt_dff_args += " -keepdc";
+ continue;
+ }
+ if (args[argidx] == "-nodffe") {
+ opt_dff_args += " -nodffe";
+ continue;
+ }
+ if (args[argidx] == "-nosdff") {
+ opt_dff_args += " -nosdff";
continue;
}
if (args[argidx] == "-sat") {
- opt_rmdff_args += " -sat";
+ opt_dff_args += " -sat";
continue;
}
if (args[argidx] == "-share_all") {
@@ -127,6 +136,10 @@ struct OptPass : public Pass {
fast_mode = true;
continue;
}
+ if (args[argidx] == "-noff") {
+ noff_mode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -137,7 +150,8 @@ struct OptPass : public Pass {
Pass::call(design, "opt_expr" + opt_expr_args);
Pass::call(design, "opt_merge" + opt_merge_args);
design->scratchpad_unset("opt.did_something");
- Pass::call(design, "opt_rmdff" + opt_rmdff_args);
+ if (!noff_mode)
+ Pass::call(design, "opt_dff" + opt_dff_args);
if (design->scratchpad_get_bool("opt.did_something") == false)
break;
Pass::call(design, "opt_clean" + opt_clean_args);
@@ -156,7 +170,8 @@ struct OptPass : public Pass {
Pass::call(design, "opt_merge" + opt_merge_args);
if (opt_share)
Pass::call(design, "opt_share");
- Pass::call(design, "opt_rmdff" + opt_rmdff_args);
+ if (!noff_mode)
+ Pass::call(design, "opt_dff" + opt_dff_args);
Pass::call(design, "opt_clean" + opt_clean_args);
Pass::call(design, "opt_expr" + opt_expr_args);
if (design->scratchpad_get_bool("opt.did_something") == false)
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index f7de02164..883374cf6 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -59,6 +59,11 @@ struct keep_cache_t
found_keep = true;
break;
}
+ for (auto wire : module->wires())
+ if (wire->get_bool_attribute(ID::keep)) {
+ found_keep = true;
+ break;
+ }
cache[module] = found_keep;
}
@@ -67,7 +72,7 @@ struct keep_cache_t
bool query(Cell *cell, bool ignore_specify = false)
{
- if (cell->type.in(ID($memwr), ID($meminit), ID($assert), ID($assume), ID($live), ID($fair), ID($cover)))
+ if (cell->type.in(ID($assert), ID($assume), ID($live), ID($fair), ID($cover)))
return true;
if (!ignore_specify && cell->type.in(ID($specify2), ID($specify3), ID($specrule)))
@@ -90,6 +95,8 @@ int count_rm_cells, count_rm_wires;
void rmunused_module_cells(Module *module, bool verbose)
{
SigMap sigmap(module);
+ dict<IdString, pool<Cell*>> mem2cells;
+ pool<IdString> mem_unused;
pool<Cell*> queue, unused;
pool<SigBit> used_raw_bits;
dict<SigBit, pool<Cell*>> wire2driver;
@@ -103,6 +110,17 @@ void rmunused_module_cells(Module *module, bool verbose)
}
}
+ for (auto &it : module->memories) {
+ mem_unused.insert(it.first);
+ }
+
+ for (Cell *cell : module->cells()) {
+ if (cell->type.in(ID($memwr), ID($meminit))) {
+ IdString mem_id = cell->getParam(ID::MEMID).decode_string();
+ mem2cells[mem_id].insert(cell);
+ }
+ }
+
for (auto &it : module->cells_) {
Cell *cell = it.second;
for (auto &it2 : cell->connections()) {
@@ -140,17 +158,33 @@ void rmunused_module_cells(Module *module, bool verbose)
while (!queue.empty())
{
pool<SigBit> bits;
- for (auto cell : queue)
- for (auto &it : cell->connections())
- if (!ct_all.cell_known(cell->type) || ct_all.cell_input(cell->type, it.first))
- for (auto bit : sigmap(it.second))
- bits.insert(bit);
+ pool<IdString> mems;
+ for (auto cell : queue) {
+ for (auto &it : cell->connections())
+ if (!ct_all.cell_known(cell->type) || ct_all.cell_input(cell->type, it.first))
+ for (auto bit : sigmap(it.second))
+ bits.insert(bit);
+
+ if (cell->type == ID($memrd)) {
+ IdString mem_id = cell->getParam(ID::MEMID).decode_string();
+ if (mem_unused.count(mem_id)) {
+ mem_unused.erase(mem_id);
+ mems.insert(mem_id);
+ }
+ }
+ }
queue.clear();
+
for (auto bit : bits)
for (auto c : wire2driver[bit])
if (unused.count(c))
queue.insert(c), unused.erase(c);
+
+ for (auto mem : mems)
+ for (auto c : mem2cells[mem])
+ if (unused.count(c))
+ queue.insert(c), unused.erase(c);
}
unused.sort(RTLIL::sort_by_name_id<RTLIL::Cell>());
@@ -163,6 +197,14 @@ void rmunused_module_cells(Module *module, bool verbose)
count_rm_cells++;
}
+ for (auto it : mem_unused)
+ {
+ if (verbose)
+ log_debug(" removing unused memory `%s'.\n", it.c_str());
+ delete module->memories.at(it);
+ module->memories.erase(it);
+ }
+
for (auto &it : module->cells_) {
Cell *cell = it.second;
for (auto &it2 : cell->connections()) {
@@ -202,7 +244,7 @@ bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPoo
if ((w1->port_input && w1->port_output) != (w2->port_input && w2->port_output))
return !(w2->port_input && w2->port_output);
- if (w1->name[0] == '\\' && w2->name[0] == '\\') {
+ if (w1->name.isPublic() && w2->name.isPublic()) {
if (regs.check(s1) != regs.check(s2))
return regs.check(s2);
if (direct_wires.count(w1) != direct_wires.count(w2))
@@ -215,7 +257,7 @@ bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPoo
return w2->port_output;
if (w1->name[0] != w2->name[0])
- return w2->name[0] == '\\';
+ return w2->name.isPublic();
int attrs1 = count_nontrivial_wire_attrs(w1);
int attrs2 = count_nontrivial_wire_attrs(w2);
@@ -526,7 +568,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
struct OptCleanPass : public Pass {
OptCleanPass() : Pass("opt_clean", "remove unused cells and wires") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -543,7 +585,7 @@ struct OptCleanPass : public Pass {
log(" also remove internal nets if they have a public name\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool purge_mode = false;
@@ -592,7 +634,7 @@ struct OptCleanPass : public Pass {
struct CleanPass : public Pass {
CleanPass() : Pass("clean", "remove unused cells and wires") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -607,7 +649,7 @@ struct CleanPass : public Pass {
log("in -purge mode between the commands.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool purge_mode = false;
diff --git a/passes/opt/opt_demorgan.cc b/passes/opt/opt_demorgan.cc
index 4bc82815b..f0fa86f42 100644
--- a/passes/opt/opt_demorgan.cc
+++ b/passes/opt/opt_demorgan.cc
@@ -169,7 +169,7 @@ void demorgan_worker(
struct OptDemorganPass : public Pass {
OptDemorganPass() : Pass("opt_demorgan", "Optimize reductions with DeMorgan equivalents") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -179,7 +179,7 @@ struct OptDemorganPass : public Pass {
log("overall gate count of the circuit\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing OPT_DEMORGAN pass (push inverters through $reduce_* cells).\n");
diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc
new file mode 100644
index 000000000..a47071a30
--- /dev/null
+++ b/passes/opt/opt_dff.cc
@@ -0,0 +1,875 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2020 Marcelina Kościelnicka <mwk@0x04.net>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/log.h"
+#include "kernel/register.h"
+#include "kernel/rtlil.h"
+#include "kernel/satgen.h"
+#include "kernel/sigtools.h"
+#include "kernel/ffinit.h"
+#include "kernel/ff.h"
+#include "passes/techmap/simplemap.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct OptDffOptions
+{
+ bool nosdff;
+ bool nodffe;
+ bool simple_dffe;
+ bool sat;
+ bool keepdc;
+};
+
+struct OptDffWorker
+{
+ const OptDffOptions &opt;
+
+ Module *module;
+ typedef std::pair<RTLIL::Cell*, int> cell_int_t;
+ SigMap sigmap;
+ FfInitVals initvals;
+ dict<SigBit, int> bitusers;
+ dict<SigBit, cell_int_t> bit2mux;
+ dict<SigBit, RTLIL::Cell*> bit2driver;
+
+ typedef std::map<RTLIL::SigBit, bool> pattern_t;
+ typedef std::set<pattern_t> patterns_t;
+ typedef std::pair<RTLIL::SigBit, bool> ctrl_t;
+ typedef std::set<ctrl_t> ctrls_t;
+
+ ezSatPtr ez;
+ SatGen satgen;
+ pool<Cell*> sat_cells;
+
+ // Used as a queue.
+ std::vector<Cell *> dff_cells;
+
+ OptDffWorker(const OptDffOptions &opt, Module *mod) : opt(opt), module(mod), sigmap(mod), initvals(&sigmap, mod), ez(), satgen(ez.get(), &sigmap) {
+ // Gathering three kinds of information here for every sigmapped SigBit:
+ //
+ // - bitusers: how many users it has (muxes will only be merged into FFs if this is 1, making the FF the only user)
+ // - bit2mux: the mux cell and bit index that drives it, if any
+ // - bit2driver: the cell driving it, if any
+
+ for (auto wire : module->wires())
+ {
+ if (wire->port_output)
+ for (auto bit : sigmap(wire))
+ bitusers[bit]++;
+ }
+
+ for (auto cell : module->cells()) {
+ if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_))) {
+ RTLIL::SigSpec sig_y = sigmap(cell->getPort(ID::Y));
+ for (int i = 0; i < GetSize(sig_y); i++)
+ bit2mux[sig_y[i]] = cell_int_t(cell, i);
+ }
+
+ for (auto conn : cell->connections()) {
+ bool is_output = cell->output(conn.first);
+ if (is_output) {
+ for (auto bit : sigmap(conn.second))
+ bit2driver[bit] = cell;
+ }
+ if (!is_output || !cell->known()) {
+ for (auto bit : sigmap(conn.second))
+ bitusers[bit]++;
+ }
+ }
+
+ if (module->design->selected(module, cell) && RTLIL::builtin_ff_cell_types().count(cell->type))
+ dff_cells.push_back(cell);
+ }
+
+ }
+
+ std::function<void(Cell*)> sat_import_cell = [&](Cell *c) {
+ if (!sat_cells.insert(c).second)
+ return;
+ if (!satgen.importCell(c))
+ return;
+ for (auto &conn : c->connections()) {
+ if (!c->input(conn.first))
+ continue;
+ for (auto bit : sigmap(conn.second))
+ if (bit2driver.count(bit))
+ sat_import_cell(bit2driver.at(bit));
+ }
+ };
+
+ State combine_const(State a, State b) {
+ if (a == State::Sx && !opt.keepdc)
+ return b;
+ if (b == State::Sx && !opt.keepdc)
+ return a;
+ if (a == b)
+ return a;
+ return State::Sm;
+ }
+
+ patterns_t find_muxtree_feedback_patterns(RTLIL::SigBit d, RTLIL::SigBit q, pattern_t path)
+ {
+ patterns_t ret;
+
+ if (d == q) {
+ ret.insert(path);
+ return ret;
+ }
+
+ if (bit2mux.count(d) == 0 || bitusers[d] > 1)
+ return ret;
+
+ cell_int_t mbit = bit2mux.at(d);
+ RTLIL::SigSpec sig_a = sigmap(mbit.first->getPort(ID::A));
+ RTLIL::SigSpec sig_b = sigmap(mbit.first->getPort(ID::B));
+ RTLIL::SigSpec sig_s = sigmap(mbit.first->getPort(ID::S));
+ int width = GetSize(sig_a), index = mbit.second;
+
+ for (int i = 0; i < GetSize(sig_s); i++)
+ if (path.count(sig_s[i]) && path.at(sig_s[i]))
+ {
+ ret = find_muxtree_feedback_patterns(sig_b[i*width + index], q, path);
+
+ if (sig_b[i*width + index] == q) {
+ RTLIL::SigSpec s = mbit.first->getPort(ID::B);
+ s[i*width + index] = RTLIL::Sx;
+ mbit.first->setPort(ID::B, s);
+ }
+
+ return ret;
+ }
+
+ pattern_t path_else = path;
+
+ for (int i = 0; i < GetSize(sig_s); i++)
+ {
+ if (path.count(sig_s[i]))
+ continue;
+
+ pattern_t path_this = path;
+ path_else[sig_s[i]] = false;
+ path_this[sig_s[i]] = true;
+
+ for (auto &pat : find_muxtree_feedback_patterns(sig_b[i*width + index], q, path_this))
+ ret.insert(pat);
+
+ if (sig_b[i*width + index] == q) {
+ RTLIL::SigSpec s = mbit.first->getPort(ID::B);
+ s[i*width + index] = RTLIL::Sx;
+ mbit.first->setPort(ID::B, s);
+ }
+ }
+
+ for (auto &pat : find_muxtree_feedback_patterns(sig_a[index], q, path_else))
+ ret.insert(pat);
+
+ if (sig_a[index] == q) {
+ RTLIL::SigSpec s = mbit.first->getPort(ID::A);
+ s[index] = RTLIL::Sx;
+ mbit.first->setPort(ID::A, s);
+ }
+
+ return ret;
+ }
+
+ void simplify_patterns(patterns_t&)
+ {
+ // TBD
+ }
+
+ ctrl_t make_patterns_logic(const patterns_t &patterns, const ctrls_t &ctrls, bool make_gates)
+ {
+ if (patterns.empty() && GetSize(ctrls) == 1) {
+ return *ctrls.begin();
+ }
+
+ RTLIL::SigSpec or_input;
+
+ for (auto pat : patterns)
+ {
+ RTLIL::SigSpec s1, s2;
+ for (auto it : pat) {
+ s1.append(it.first);
+ s2.append(it.second);
+ }
+
+ RTLIL::SigSpec y = module->addWire(NEW_ID);
+ RTLIL::Cell *c = module->addNe(NEW_ID, s1, s2, y);
+
+ if (make_gates) {
+ simplemap(module, c);
+ module->remove(c);
+ }
+
+ or_input.append(y);
+ }
+ for (auto item : ctrls) {
+ if (item.second)
+ or_input.append(item.first);
+ else if (make_gates)
+ or_input.append(module->NotGate(NEW_ID, item.first));
+ else
+ or_input.append(module->Not(NEW_ID, item.first));
+ }
+
+ if (GetSize(or_input) == 0)
+ return ctrl_t(State::S1, true);
+
+ if (GetSize(or_input) == 1)
+ return ctrl_t(or_input, true);
+
+ RTLIL::SigSpec y = module->addWire(NEW_ID);
+ RTLIL::Cell *c = module->addReduceAnd(NEW_ID, or_input, y);
+
+ if (make_gates) {
+ simplemap(module, c);
+ module->remove(c);
+ }
+
+ return ctrl_t(y, true);
+ }
+
+ ctrl_t combine_resets(const ctrls_t &ctrls, bool make_gates)
+ {
+ if (GetSize(ctrls) == 1) {
+ return *ctrls.begin();
+ }
+
+ RTLIL::SigSpec or_input;
+
+ bool final_pol = false;
+ for (auto item : ctrls) {
+ if (item.second)
+ final_pol = true;
+ }
+
+ for (auto item : ctrls) {
+ if (item.second == final_pol)
+ or_input.append(item.first);
+ else if (make_gates)
+ or_input.append(module->NotGate(NEW_ID, item.first));
+ else
+ or_input.append(module->Not(NEW_ID, item.first));
+ }
+
+ RTLIL::SigSpec y = module->addWire(NEW_ID);
+ RTLIL::Cell *c = final_pol ? module->addReduceOr(NEW_ID, or_input, y) : module->addReduceAnd(NEW_ID, or_input, y);
+
+ if (make_gates) {
+ simplemap(module, c);
+ module->remove(c);
+ }
+
+ return ctrl_t(y, final_pol);
+ }
+
+ bool run() {
+ // We have all the information we need, and the list of FFs to process as well. Do it.
+ bool did_something = false;
+ while (!dff_cells.empty()) {
+ Cell *cell = dff_cells.back();
+ dff_cells.pop_back();
+ // Break down the FF into pieces.
+ FfData ff(&initvals, cell);
+ bool changed = false;
+
+ if (!ff.width) {
+ module->remove(cell);
+ did_something = true;
+ continue;
+ }
+
+ if (ff.has_sr) {
+ bool sr_removed = false;
+ std::vector<int> keep_bits;
+ // Check for always-active S/R bits.
+ for (int i = 0; i < ff.width; i++) {
+ if (ff.sig_clr[i] == (ff.pol_clr ? State::S1 : State::S0) || (!opt.keepdc && ff.sig_clr[i] == State::Sx)) {
+ // Always-active clear — connect Q bit to 0.
+ initvals.remove_init(ff.sig_q[i]);
+ module->connect(ff.sig_q[i], State::S0);
+ log("Handling always-active CLR at position %d on %s (%s) from module %s (changing to const driver).\n",
+ i, log_id(cell), log_id(cell->type), log_id(module));
+ sr_removed = true;
+ } else if (ff.sig_set[i] == (ff.pol_set ? State::S1 : State::S0) || (!opt.keepdc && ff.sig_set[i] == State::Sx)) {
+ // Always-active set — connect Q bit to 1 if clear inactive, 0 if reset active.
+ initvals.remove_init(ff.sig_q[i]);
+ if (!ff.pol_clr) {
+ module->connect(ff.sig_q[i], ff.sig_clr[i]);
+ } else if (ff.is_fine) {
+ module->addNotGate(NEW_ID, ff.sig_q[i], ff.sig_clr[i]);
+ } else {
+ module->addNot(NEW_ID, ff.sig_q[i], ff.sig_clr[i]);
+ }
+ log("Handling always-active SET at position %d on %s (%s) from module %s (changing to combinatorial circuit).\n",
+ i, log_id(cell), log_id(cell->type), log_id(module));
+ sr_removed = true;
+ } else {
+ keep_bits.push_back(i);
+ }
+ }
+ if (sr_removed) {
+ if (keep_bits.empty()) {
+ module->remove(cell);
+ did_something = true;
+ continue;
+ }
+ ff = ff.slice(keep_bits);
+ changed = true;
+ }
+
+ if (ff.pol_clr ? ff.sig_clr.is_fully_zero() : ff.sig_clr.is_fully_ones()) {
+ // CLR is useless, try to kill it.
+ bool failed = false;
+ for (int i = 0; i < ff.width; i++)
+ if (ff.sig_set[i] != ff.sig_set[0])
+ failed = true;
+ if (!failed) {
+ log("Removing never-active CLR on %s (%s) from module %s.\n",
+ log_id(cell), log_id(cell->type), log_id(module));
+ ff.has_sr = false;
+ ff.has_arst = true;
+ ff.pol_arst = ff.pol_set;
+ ff.sig_arst = ff.sig_set[0];
+ ff.val_arst = Const(State::S1, ff.width);
+ changed = true;
+ }
+ } else if (ff.pol_set ? ff.sig_set.is_fully_zero() : ff.sig_set.is_fully_ones()) {
+ // SET is useless, try to kill it.
+ bool failed = false;
+ for (int i = 0; i < ff.width; i++)
+ if (ff.sig_clr[i] != ff.sig_clr[0])
+ failed = true;
+ if (!failed) {
+ log("Removing never-active SET on %s (%s) from module %s.\n",
+ log_id(cell), log_id(cell->type), log_id(module));
+ ff.has_sr = false;
+ ff.has_arst = true;
+ ff.pol_arst = ff.pol_clr;
+ ff.sig_arst = ff.sig_clr[0];
+ ff.val_arst = Const(State::S0, ff.width);
+ changed = true;
+ }
+ } else if (ff.pol_clr == ff.pol_set) {
+ // Try a more complex conversion to plain async reset.
+ State val_neutral = ff.pol_set ? State::S0 : State::S1;
+ Const val_arst;
+ SigSpec sig_arst;
+ if (ff.sig_clr[0] == val_neutral)
+ sig_arst = ff.sig_set[0];
+ else
+ sig_arst = ff.sig_clr[0];
+ bool failed = false;
+ for (int i = 0; i < ff.width; i++) {
+ if (ff.sig_clr[i] == sig_arst && ff.sig_set[i] == val_neutral)
+ val_arst.bits.push_back(State::S0);
+ else if (ff.sig_set[i] == sig_arst && ff.sig_clr[i] == val_neutral)
+ val_arst.bits.push_back(State::S1);
+ else
+ failed = true;
+ }
+ if (!failed) {
+ log("Converting CLR/SET to ARST on %s (%s) from module %s.\n",
+ log_id(cell), log_id(cell->type), log_id(module));
+ ff.has_sr = false;
+ ff.has_arst = true;
+ ff.val_arst = val_arst;
+ ff.sig_arst = sig_arst;
+ ff.pol_arst = ff.pol_clr;
+ changed = true;
+ }
+ }
+ }
+
+ if (ff.has_arst) {
+ if (ff.sig_arst == (ff.pol_arst ? State::S0 : State::S1)) {
+ // Always-inactive reset — remove.
+ log("Removing never-active ARST on %s (%s) from module %s.\n",
+ log_id(cell), log_id(cell->type), log_id(module));
+ ff.has_arst = false;
+ changed = true;
+ } else if (ff.sig_arst == (ff.pol_arst ? State::S1 : State::S0) || (!opt.keepdc && ff.sig_arst == State::Sx)) {
+ // Always-active async reset — change to const driver.
+ log("Handling always-active ARST on %s (%s) from module %s (changing to const driver).\n",
+ log_id(cell), log_id(cell->type), log_id(module));
+ initvals.remove_init(ff.sig_q);
+ module->remove(cell);
+ module->connect(ff.sig_q, ff.val_arst);
+ did_something = true;
+ continue;
+ }
+ }
+
+ if (ff.has_srst) {
+ if (ff.sig_srst == (ff.pol_srst ? State::S0 : State::S1)) {
+ // Always-inactive reset — remove.
+ log("Removing never-active SRST on %s (%s) from module %s.\n",
+ log_id(cell), log_id(cell->type), log_id(module));
+ ff.has_srst = false;
+ changed = true;
+ } else if (ff.sig_srst == (ff.pol_srst ? State::S1 : State::S0) || (!opt.keepdc && ff.sig_srst == State::Sx)) {
+ // Always-active sync reset — connect to D instead.
+ log("Handling always-active SRST on %s (%s) from module %s (changing to const D).\n",
+ log_id(cell), log_id(cell->type), log_id(module));
+ ff.has_srst = false;
+ if (!ff.ce_over_srst)
+ ff.has_en = false;
+ ff.sig_d = ff.val_d = ff.val_srst;
+ ff.d_is_const = true;
+ changed = true;
+ }
+ }
+
+ if (ff.has_en) {
+ if (ff.sig_en == (ff.pol_en ? State::S0 : State::S1) || (!opt.keepdc && ff.sig_en == State::Sx)) {
+ // Always-inactive enable — remove.
+ if (ff.has_clk && ff.has_srst && !ff.ce_over_srst) {
+ log("Handling never-active EN on %s (%s) from module %s (connecting SRST instead).\n",
+ log_id(cell), log_id(cell->type), log_id(module));
+ // FF with sync reset — connect the sync reset to D instead.
+ ff.pol_en = ff.pol_srst;
+ ff.sig_en = ff.sig_srst;
+ ff.has_srst = false;
+ ff.sig_d = ff.val_d = ff.val_srst;
+ ff.d_is_const = true;
+ changed = true;
+ } else {
+ log("Handling never-active EN on %s (%s) from module %s (removing D path).\n",
+ log_id(cell), log_id(cell->type), log_id(module));
+ // The D input path is effectively useless, so remove it (this will be a const-input D latch, SR latch, or a const driver).
+ ff.has_d = ff.has_en = ff.has_clk = false;
+ changed = true;
+ }
+ } else if (ff.sig_en == (ff.pol_en ? State::S1 : State::S0)) {
+ // Always-active enable.
+ if (ff.has_clk) {
+ // For FF, just remove the useless enable.
+ log("Removing always-active EN on %s (%s) from module %s.\n",
+ log_id(cell), log_id(cell->type), log_id(module));
+ ff.has_en = false;
+ changed = true;
+ } else {
+ // For latches, make a comb circuit, nuke the latch.
+ log("Handling always-active EN on %s (%s) from module %s (changing to combinatorial circuit).\n",
+ log_id(cell), log_id(cell->type), log_id(module));
+ initvals.remove_init(ff.sig_q);
+ module->remove(cell);
+ if (ff.has_sr) {
+ SigSpec tmp;
+ if (ff.is_fine) {
+ if (ff.pol_set)
+ tmp = module->MuxGate(NEW_ID, ff.sig_d, State::S1, ff.sig_set);
+ else
+ tmp = module->MuxGate(NEW_ID, State::S1, ff.sig_d, ff.sig_set);
+ if (ff.pol_clr)
+ module->addMuxGate(NEW_ID, tmp, State::S0, ff.sig_clr, ff.sig_q);
+ else
+ module->addMuxGate(NEW_ID, State::S0, tmp, ff.sig_clr, ff.sig_q);
+ } else {
+ if (ff.pol_set)
+ tmp = module->Or(NEW_ID, ff.sig_d, ff.sig_set);
+ else
+ tmp = module->Or(NEW_ID, ff.sig_d, module->Not(NEW_ID, ff.sig_set));
+ if (ff.pol_clr)
+ module->addAnd(NEW_ID, tmp, module->Not(NEW_ID, ff.sig_clr), ff.sig_q);
+ else
+ module->addAnd(NEW_ID, tmp, ff.sig_clr, ff.sig_q);
+ }
+ } else if (ff.has_arst) {
+ if (ff.is_fine) {
+ if (ff.pol_arst)
+ module->addMuxGate(NEW_ID, ff.sig_d, ff.val_arst[0], ff.sig_arst, ff.sig_q);
+ else
+ module->addMuxGate(NEW_ID, ff.val_arst[0], ff.sig_d, ff.sig_arst, ff.sig_q);
+ } else {
+ if (ff.pol_arst)
+ module->addMux(NEW_ID, ff.sig_d, ff.val_arst, ff.sig_arst, ff.sig_q);
+ else
+ module->addMux(NEW_ID, ff.val_arst, ff.sig_d, ff.sig_arst, ff.sig_q);
+ }
+ } else {
+ module->connect(ff.sig_q, ff.sig_d);
+ }
+ did_something = true;
+ continue;
+ }
+ }
+ }
+
+ if (ff.has_clk) {
+ if (ff.sig_clk.is_fully_const()) {
+ // Const clock — the D input path is effectively useless, so remove it (this will be a const-input D latch, SR latch, or a const driver).
+ log("Handling const CLK on %s (%s) from module %s (removing D path).\n",
+ log_id(cell), log_id(cell->type), log_id(module));
+ ff.has_d = ff.has_en = ff.has_clk = ff.has_srst = false;
+ changed = true;
+ }
+ }
+
+ if (ff.has_d && ff.sig_d == ff.sig_q) {
+ // Q wrapped back to D, can be removed.
+ if (ff.has_clk && ff.has_srst) {
+ // FF with sync reset — connect the sync reset to D instead.
+ log("Handling D = Q on %s (%s) from module %s (conecting SRST instead).\n",
+ log_id(cell), log_id(cell->type), log_id(module));
+ if (ff.has_en && ff.ce_over_srst) {
+ if (!ff.pol_en) {
+ if (ff.is_fine)
+ ff.sig_en = module->NotGate(NEW_ID, ff.sig_en);
+ else
+ ff.sig_en = module->Not(NEW_ID, ff.sig_en);
+ }
+ if (!ff.pol_srst) {
+ if (ff.is_fine)
+ ff.sig_srst = module->NotGate(NEW_ID, ff.sig_srst);
+ else
+ ff.sig_srst = module->Not(NEW_ID, ff.sig_srst);
+ }
+ if (ff.is_fine)
+ ff.sig_en = module->AndGate(NEW_ID, ff.sig_en, ff.sig_srst);
+ else
+ ff.sig_en = module->And(NEW_ID, ff.sig_en, ff.sig_srst);
+ ff.pol_en = true;
+ } else {
+ ff.pol_en = ff.pol_srst;
+ ff.sig_en = ff.sig_srst;
+ }
+ ff.has_en = true;
+ ff.has_srst = false;
+ ff.sig_d = ff.val_d = ff.val_srst;
+ ff.d_is_const = true;
+ changed = true;
+ } else {
+ // The D input path is effectively useless, so remove it (this will be a const-input D latch, SR latch, or a const driver).
+ log("Handling D = Q on %s (%s) from module %s (removing D path).\n",
+ log_id(cell), log_id(cell->type), log_id(module));
+ ff.has_d = ff.has_en = ff.has_clk = false;
+ changed = true;
+ }
+ }
+
+ // Now check if any bit can be replaced by a constant.
+ pool<int> removed_sigbits;
+ for (int i = 0; i < ff.width; i++) {
+ State val = ff.val_init[i];
+ if (ff.has_arst)
+ val = combine_const(val, ff.val_arst[i]);
+ if (ff.has_srst)
+ val = combine_const(val, ff.val_srst[i]);
+ if (ff.has_sr) {
+ if (ff.sig_clr[i] != (ff.pol_clr ? State::S0 : State::S1))
+ val = combine_const(val, State::S0);
+ if (ff.sig_set[i] != (ff.pol_set ? State::S0 : State::S1))
+ val = combine_const(val, State::S1);
+ }
+ if (val == State::Sm)
+ continue;
+ if (ff.has_d) {
+ if (!ff.sig_d[i].wire) {
+ val = combine_const(val, ff.sig_d[i].data);
+ if (val == State::Sm)
+ continue;
+ } else {
+ if (!opt.sat)
+ continue;
+ // For each register bit, try to prove that it cannot change from the initial value. If so, remove it
+ if (!bit2driver.count(ff.sig_d[i]))
+ continue;
+ if (val != State::S0 && val != State::S1)
+ continue;
+
+ sat_import_cell(bit2driver.at(ff.sig_d[i]));
+
+ int init_sat_pi = satgen.importSigSpec(val).front();
+ int q_sat_pi = satgen.importSigBit(ff.sig_q[i]);
+ int d_sat_pi = satgen.importSigBit(ff.sig_d[i]);
+
+ // Try to find out whether the register bit can change under some circumstances
+ bool counter_example_found = ez->solve(ez->IFF(q_sat_pi, init_sat_pi), ez->NOT(ez->IFF(d_sat_pi, init_sat_pi)));
+
+ // If the register bit cannot change, we can replace it with a constant
+ if (counter_example_found)
+ continue;
+ }
+ }
+ log("Setting constant %d-bit at position %d on %s (%s) from module %s.\n", val ? 1 : 0,
+ i, log_id(cell), log_id(cell->type), log_id(module));
+
+ initvals.remove_init(ff.sig_q[i]);
+ module->connect(ff.sig_q[i], val);
+ removed_sigbits.insert(i);
+ }
+ if (!removed_sigbits.empty()) {
+ std::vector<int> keep_bits;
+ for (int i = 0; i < ff.width; i++)
+ if (!removed_sigbits.count(i))
+ keep_bits.push_back(i);
+ if (keep_bits.empty()) {
+ module->remove(cell);
+ did_something = true;
+ continue;
+ }
+ ff = ff.slice(keep_bits);
+ changed = true;
+ }
+
+ // The cell has been simplified as much as possible already. Now try to spice it up with enables / sync resets.
+ if (ff.has_clk) {
+ if (!ff.has_arst && !ff.has_sr && (!ff.has_srst || !ff.has_en || ff.ce_over_srst) && !opt.nosdff) {
+ // Try to merge sync resets.
+ std::map<ctrls_t, std::vector<int>> groups;
+ std::vector<int> remaining_indices;
+ Const val_srst;
+
+ for (int i = 0 ; i < ff.width; i++) {
+ ctrls_t resets;
+ State reset_val = State::Sx;
+ if (ff.has_srst)
+ reset_val = ff.val_srst[i];
+ while (bit2mux.count(ff.sig_d[i]) && bitusers[ff.sig_d[i]] == 1) {
+ cell_int_t mbit = bit2mux.at(ff.sig_d[i]);
+ if (GetSize(mbit.first->getPort(ID::S)) != 1)
+ break;
+ SigBit s = mbit.first->getPort(ID::S);
+ SigBit a = mbit.first->getPort(ID::A)[mbit.second];
+ SigBit b = mbit.first->getPort(ID::B)[mbit.second];
+ // Workaround for funny memory WE pattern.
+ if ((a == State::S0 || a == State::S1) && (b == State::S0 || b == State::S1))
+ break;
+ if ((b == State::S0 || b == State::S1) && (b == reset_val || reset_val == State::Sx)) {
+ // This is better handled by CE pattern.
+ if (a == ff.sig_q[i])
+ break;
+ reset_val = b.data;
+ resets.insert(ctrl_t(s, true));
+ ff.sig_d[i] = a;
+ } else if ((a == State::S0 || a == State::S1) && (a == reset_val || reset_val == State::Sx)) {
+ // This is better handled by CE pattern.
+ if (b == ff.sig_q[i])
+ break;
+ reset_val = a.data;
+ resets.insert(ctrl_t(s, false));
+ ff.sig_d[i] = b;
+ } else {
+ break;
+ }
+ }
+
+ if (!resets.empty()) {
+ if (ff.has_srst)
+ resets.insert(ctrl_t(ff.sig_srst, ff.pol_srst));
+ groups[resets].push_back(i);
+ } else
+ remaining_indices.push_back(i);
+ val_srst.bits.push_back(reset_val);
+ }
+
+ for (auto &it : groups) {
+ FfData new_ff = ff.slice(it.second);
+ new_ff.val_srst = Const();
+ for (int i = 0; i < new_ff.width; i++) {
+ int j = it.second[i];
+ new_ff.val_srst.bits.push_back(val_srst[j]);
+ }
+ ctrl_t srst = combine_resets(it.first, ff.is_fine);
+
+ new_ff.has_srst = true;
+ new_ff.sig_srst = srst.first;
+ new_ff.pol_srst = srst.second;
+ if (new_ff.has_en)
+ new_ff.ce_over_srst = true;
+ Cell *new_cell = new_ff.emit(module, NEW_ID);
+ if (new_cell)
+ dff_cells.push_back(new_cell);
+ log("Adding SRST signal on %s (%s) from module %s (D = %s, Q = %s, rval = %s).\n",
+ log_id(cell), log_id(cell->type), log_id(module), log_signal(new_ff.sig_d), log_signal(new_ff.sig_q), log_signal(new_ff.val_srst));
+ }
+
+ if (remaining_indices.empty()) {
+ module->remove(cell);
+ did_something = true;
+ continue;
+ } else if (GetSize(remaining_indices) != ff.width) {
+ ff = ff.slice(remaining_indices);
+ changed = true;
+ }
+ }
+ if ((!ff.has_srst || !ff.has_en || !ff.ce_over_srst) && !opt.nodffe) {
+ // Try to merge enables.
+ std::map<std::pair<patterns_t, ctrls_t>, std::vector<int>> groups;
+ std::vector<int> remaining_indices;
+
+ for (int i = 0 ; i < ff.width; i++) {
+ // First, eat up as many simple muxes as possible.
+ ctrls_t enables;
+ while (bit2mux.count(ff.sig_d[i]) && bitusers[ff.sig_d[i]] == 1) {
+ cell_int_t mbit = bit2mux.at(ff.sig_d[i]);
+ if (GetSize(mbit.first->getPort(ID::S)) != 1)
+ break;
+ SigBit s = mbit.first->getPort(ID::S);
+ SigBit a = mbit.first->getPort(ID::A)[mbit.second];
+ SigBit b = mbit.first->getPort(ID::B)[mbit.second];
+ if (a == ff.sig_q[i]) {
+ enables.insert(ctrl_t(s, true));
+ ff.sig_d[i] = b;
+ } else if (b == ff.sig_q[i]) {
+ enables.insert(ctrl_t(s, false));
+ ff.sig_d[i] = a;
+ } else {
+ break;
+ }
+ }
+
+ patterns_t patterns;
+ if (!opt.simple_dffe)
+ patterns = find_muxtree_feedback_patterns(ff.sig_d[i], ff.sig_q[i], pattern_t());
+ if (!patterns.empty() || !enables.empty()) {
+ if (ff.has_en)
+ enables.insert(ctrl_t(ff.sig_en, ff.pol_en));
+ simplify_patterns(patterns);
+ groups[std::make_pair(patterns, enables)].push_back(i);
+ } else
+ remaining_indices.push_back(i);
+ }
+
+ for (auto &it : groups) {
+ FfData new_ff = ff.slice(it.second);
+ ctrl_t en = make_patterns_logic(it.first.first, it.first.second, ff.is_fine);
+
+ new_ff.has_en = true;
+ new_ff.sig_en = en.first;
+ new_ff.pol_en = en.second;
+ new_ff.ce_over_srst = false;
+ Cell *new_cell = new_ff.emit(module, NEW_ID);
+ if (new_cell)
+ dff_cells.push_back(new_cell);
+ log("Adding EN signal on %s (%s) from module %s (D = %s, Q = %s).\n",
+ log_id(cell), log_id(cell->type), log_id(module), log_signal(new_ff.sig_d), log_signal(new_ff.sig_q));
+ }
+
+ if (remaining_indices.empty()) {
+ module->remove(cell);
+ did_something = true;
+ continue;
+ } else if (GetSize(remaining_indices) != ff.width) {
+ ff = ff.slice(remaining_indices);
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ // Rebuild the FF.
+ IdString name = cell->name;
+ module->remove(cell);
+ ff.emit(module, name);
+ did_something = true;
+ }
+ }
+ return did_something;
+ }
+};
+
+struct OptDffPass : public Pass {
+ OptDffPass() : Pass("opt_dff", "perform DFF optimizations") { }
+ void help() override
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" opt_dff [-nodffe] [-nosdff] [-keepdc] [-sat] [selection]\n");
+ log("\n");
+ log("This pass converts flip-flops to a more suitable type by merging clock enables\n");
+ log("and synchronous reset multiplexers, removing unused control inputs, or potentially\n");
+ log("removes the flip-flop altogether, converting it to a constant driver.\n");
+ log("\n");
+ log(" -nodffe\n");
+ log(" disables dff -> dffe conversion, and other transforms recognizing clock enable\n");
+ log("\n");
+ log(" -nosdff\n");
+ log(" disables dff -> sdff conversion, and other transforms recognizing sync resets\n");
+ log("\n");
+ log(" -simple-dffe\n");
+ log(" only enables clock enable recognition transform for obvious cases\n");
+ log("\n");
+ log(" -sat\n");
+ log(" additionally invoke SAT solver to detect and remove flip-flops (with\n");
+ log(" non-constant inputs) that can also be replaced with a constant driver\n");
+ log("\n");
+ log(" -keepdc\n");
+ log(" some optimizations change the behavior of the circuit with respect to\n");
+ log(" don't-care bits. for example in 'a+0' a single x-bit in 'a' will cause\n");
+ log(" all result bits to be set to x. this behavior changes when 'a+0' is\n");
+ log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n");
+ log("\n");
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
+ {
+ log_header(design, "Executing OPT_DFF pass (perform DFF optimizations).\n");
+ OptDffOptions opt;
+ opt.nodffe = false;
+ opt.nosdff = false;
+ opt.simple_dffe = false;
+ opt.keepdc = false;
+ opt.sat = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-nodffe") {
+ opt.nodffe = true;
+ continue;
+ }
+ if (args[argidx] == "-nosdff") {
+ opt.nosdff = true;
+ continue;
+ }
+ if (args[argidx] == "-simple-dffe") {
+ opt.simple_dffe = true;
+ continue;
+ }
+ if (args[argidx] == "-keepdc") {
+ opt.keepdc = true;
+ continue;
+ }
+ if (args[argidx] == "-sat") {
+ opt.sat = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ bool did_something = false;
+ for (auto mod : design->selected_modules()) {
+ OptDffWorker worker(opt, mod);
+ if (worker.run())
+ did_something = true;
+ }
+
+ if (did_something)
+ design->scratchpad_set_bool("opt.did_something", true);
+ }
+} OptDffPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index e5b8bda95..e36e4419d 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -117,7 +117,7 @@ void replace_undriven(RTLIL::Module *module, const CellTypes &ct)
}
void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell,
- const std::string &info YS_ATTRIBUTE(unused), IdString out_port, RTLIL::SigSpec out_val)
+ const std::string &info, IdString out_port, RTLIL::SigSpec out_val)
{
RTLIL::SigSpec Y = cell->getPort(out_port);
out_val.extend_u0(Y.size(), false);
@@ -416,7 +416,7 @@ int get_onehot_bit_index(RTLIL::SigSpec signal)
return bit_index;
}
-void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc, bool clkinv)
+void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc, bool noclkinv)
{
if (!design->selected(module))
return;
@@ -465,17 +465,23 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
#define ACTION_DO(_p_, _s_) do { cover("opt.opt_expr.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
#define ACTION_DO_Y(_v_) ACTION_DO(ID::Y, RTLIL::SigSpec(RTLIL::State::S ## _v_))
- if (clkinv)
+ if (!noclkinv)
{
- if (cell->type.in(ID($dff), ID($dffe), ID($dffsr), ID($adff), ID($fsm), ID($memrd), ID($memwr)))
+ if (cell->type.in(ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($sdff), ID($sdffe), ID($sdffce), ID($fsm), ID($memrd), ID($memwr)))
handle_polarity_inv(cell, ID::CLK, ID::CLK_POLARITY, assign_map, invert_map);
- if (cell->type.in(ID($sr), ID($dffsr), ID($dlatchsr))) {
+ if (cell->type.in(ID($sr), ID($dffsr), ID($dffsre), ID($dlatchsr))) {
handle_polarity_inv(cell, ID::SET, ID::SET_POLARITY, assign_map, invert_map);
handle_polarity_inv(cell, ID::CLR, ID::CLR_POLARITY, assign_map, invert_map);
}
- if (cell->type.in(ID($dffe), ID($dlatch), ID($dlatchsr)))
+ if (cell->type.in(ID($adff), ID($adffe), ID($adlatch)))
+ handle_polarity_inv(cell, ID::ARST, ID::ARST_POLARITY, assign_map, invert_map);
+
+ if (cell->type.in(ID($sdff), ID($sdffe), ID($sdffce)))
+ handle_polarity_inv(cell, ID::SRST, ID::SRST_POLARITY, assign_map, invert_map);
+
+ if (cell->type.in(ID($dffe), ID($adffe), ID($sdffe), ID($sdffce), ID($dffsre), ID($dlatch), ID($adlatch), ID($dlatchsr)))
handle_polarity_inv(cell, ID::EN, ID::EN_POLARITY, assign_map, invert_map);
handle_clkpol_celltype_swap(cell, "$_SR_N?_", "$_SR_P?_", ID::S, assign_map, invert_map);
@@ -489,12 +495,35 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
handle_clkpol_celltype_swap(cell, "$_DFF_N??_", "$_DFF_P??_", ID::C, assign_map, invert_map);
handle_clkpol_celltype_swap(cell, "$_DFF_?N?_", "$_DFF_?P?_", ID::R, assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DFFE_N???_", "$_DFFE_P???_", ID::C, assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DFFE_?N??_", "$_DFFE_?P??_", ID::R, assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DFFE_???N_", "$_DFFE_???P_", ID::E, assign_map, invert_map);
+
+ handle_clkpol_celltype_swap(cell, "$_SDFF_N??_", "$_SDFF_P??_", ID::C, assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_SDFF_?N?_", "$_SDFF_?P?_", ID::R, assign_map, invert_map);
+
+ handle_clkpol_celltype_swap(cell, "$_SDFFE_N???_", "$_SDFFE_P???_", ID::C, assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_SDFFE_?N??_", "$_SDFFE_?P??_", ID::R, assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_SDFFE_???N_", "$_SDFFE_???P_", ID::E, assign_map, invert_map);
+
+ handle_clkpol_celltype_swap(cell, "$_SDFFCE_N???_", "$_SDFFCE_P???_", ID::C, assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_SDFFCE_?N??_", "$_SDFFCE_?P??_", ID::R, assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_SDFFCE_???N_", "$_SDFFCE_???P_", ID::E, assign_map, invert_map);
+
handle_clkpol_celltype_swap(cell, "$_DFFSR_N??_", "$_DFFSR_P??_", ID::C, assign_map, invert_map);
handle_clkpol_celltype_swap(cell, "$_DFFSR_?N?_", "$_DFFSR_?P?_", ID::S, assign_map, invert_map);
handle_clkpol_celltype_swap(cell, "$_DFFSR_??N_", "$_DFFSR_??P_", ID::R, assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DFFSRE_N???_", "$_DFFSRE_P???_", ID::C, assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DFFSRE_?N??_", "$_DFFSRE_?P??_", ID::S, assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DFFSRE_??N?_", "$_DFFSRE_??P?_", ID::R, assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DFFSRE_???N_", "$_DFFSRE_???P_", ID::E, assign_map, invert_map);
+
handle_clkpol_celltype_swap(cell, "$_DLATCH_N_", "$_DLATCH_P_", ID::E, assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DLATCH_N??_", "$_DLATCH_P??_", ID::E, assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DLATCH_?N?_", "$_DLATCH_?P?_", ID::R, assign_map, invert_map);
+
handle_clkpol_celltype_swap(cell, "$_DLATCHSR_N??_", "$_DLATCHSR_P??_", ID::E, assign_map, invert_map);
handle_clkpol_celltype_swap(cell, "$_DLATCHSR_?N?_", "$_DLATCHSR_?P?_", ID::S, assign_map, invert_map);
handle_clkpol_celltype_swap(cell, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", ID::R, assign_map, invert_map);
@@ -575,7 +604,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (cell->type.in(ID($xnor), ID($_XNOR_))) {
cover("opt.opt_expr.const_xnor");
// For consistency since simplemap does $xnor -> $_XOR_ + $_NOT_
- int width = cell->getParam(ID::Y_WIDTH).as_int();
+ int width = GetSize(cell->getPort(ID::Y));
replace_cell(assign_map, module, cell, "const_xnor", ID::Y, SigSpec(RTLIL::State::S1, width));
goto next_cell;
}
@@ -1567,6 +1596,14 @@ skip_identity:
log_debug("Removing low %d A and %d B bits from cell `%s' in module `%s'.\n",
a_zeros, b_zeros, cell->name.c_str(), module->name.c_str());
+ if (y_zeros >= GetSize(sig_y)) {
+ module->connect(sig_y, RTLIL::SigSpec(0, GetSize(sig_y)));
+ module->remove(cell);
+
+ did_something = true;
+ goto next_cell;
+ }
+
if (a_zeros) {
cell->setPort(ID::A, sig_a.extract_end(a_zeros));
cell->parameters[ID::A_WIDTH] = GetSize(sig_a) - a_zeros;
@@ -2009,7 +2046,7 @@ skip_alu_split:
struct OptExprPass : public Pass {
OptExprPass() : Pass("opt_expr", "perform const folding and simple expression rewriting") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -2027,8 +2064,8 @@ struct OptExprPass : public Pass {
log(" -undriven\n");
log(" replace undriven nets with undef (x) constants\n");
log("\n");
- log(" -clkinv\n");
- log(" optimize clock inverters by changing FF types\n");
+ log(" -noclkinv\n");
+ log(" do not optimize clock inverters by changing FF types\n");
log("\n");
log(" -fine\n");
log(" perform fine-grain optimizations\n");
@@ -2043,12 +2080,12 @@ struct OptExprPass : public Pass {
log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool mux_undef = false;
bool mux_bool = false;
bool undriven = false;
- bool clkinv = false;
+ bool noclkinv = false;
bool do_fine = false;
bool keepdc = false;
@@ -2069,8 +2106,8 @@ struct OptExprPass : public Pass {
undriven = true;
continue;
}
- if (args[argidx] == "-clkinv") {
- clkinv = true;
+ if (args[argidx] == "-noclkinv") {
+ noclkinv = true;
continue;
}
if (args[argidx] == "-fine") {
@@ -2107,12 +2144,12 @@ struct OptExprPass : public Pass {
do {
do {
did_something = false;
- replace_const_cells(design, module, false /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, clkinv);
+ replace_const_cells(design, module, false /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, noclkinv);
if (did_something)
design->scratchpad_set_bool("opt.did_something", true);
} while (did_something);
if (!keepdc)
- replace_const_cells(design, module, true /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, clkinv);
+ replace_const_cells(design, module, true /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, noclkinv);
if (did_something)
design->scratchpad_set_bool("opt.did_something", true);
} while (did_something);
diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc
index 12927d052..07a91af8a 100644
--- a/passes/opt/opt_lut.cc
+++ b/passes/opt/opt_lut.cc
@@ -520,7 +520,7 @@ static void split(std::vector<std::string> &tokens, const std::string &text, cha
struct OptLutPass : public Pass {
OptLutPass() : Pass("opt_lut", "optimize LUT cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -538,7 +538,7 @@ struct OptLutPass : public Pass {
log(" only perform the first N combines, then stop. useful for debugging.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing OPT_LUT pass (optimize LUTs).\n");
diff --git a/passes/opt/opt_lut_ins.cc b/passes/opt/opt_lut_ins.cc
index 1d32e84bb..bb40e1e55 100644
--- a/passes/opt/opt_lut_ins.cc
+++ b/passes/opt/opt_lut_ins.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct OptLutInsPass : public Pass {
OptLutInsPass() : Pass("opt_lut_ins", "discard unused LUT inputs") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -42,7 +42,7 @@ struct OptLutInsPass : public Pass {
log(" to the given technology. Valid values are: xilinx, ecp5, gowin.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing OPT_LUT_INS pass (discard unused LUT inputs).\n");
string techname;
diff --git a/passes/opt/opt_mem.cc b/passes/opt/opt_mem.cc
index ff9c06453..49a0ac51a 100644
--- a/passes/opt/opt_mem.cc
+++ b/passes/opt/opt_mem.cc
@@ -19,85 +19,14 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
+#include "kernel/mem.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-struct OptMemWorker
-{
- RTLIL::Design *design;
- RTLIL::Module *module;
- SigMap sigmap;
- bool restart;
-
- dict<IdString, vector<IdString>> memrd, memwr, meminit;
- pool<IdString> remove_mem, remove_cells;
-
- OptMemWorker(RTLIL::Module *module) : design(module->design), module(module), sigmap(module), restart(false)
- {
- for (auto &it : module->memories)
- {
- memrd[it.first];
- memwr[it.first];
- meminit[it.first];
- }
-
- for (auto cell : module->cells())
- {
- if (cell->type == ID($memrd)) {
- IdString id = cell->getParam(ID::MEMID).decode_string();
- memrd.at(id).push_back(cell->name);
- }
-
- if (cell->type == ID($memwr)) {
- IdString id = cell->getParam(ID::MEMID).decode_string();
- memwr.at(id).push_back(cell->name);
- }
-
- if (cell->type == ID($meminit)) {
- IdString id = cell->getParam(ID::MEMID).decode_string();
- meminit.at(id).push_back(cell->name);
- }
- }
- }
-
- ~OptMemWorker()
- {
- for (auto it : remove_mem)
- {
- for (auto cell_name : memrd[it])
- module->remove(module->cell(cell_name));
- for (auto cell_name : memwr[it])
- module->remove(module->cell(cell_name));
- for (auto cell_name : meminit[it])
- module->remove(module->cell(cell_name));
-
- delete module->memories.at(it);
- module->memories.erase(it);
- }
-
- for (auto cell_name : remove_cells)
- module->remove(module->cell(cell_name));
- }
-
- int run(RTLIL::Memory *mem)
- {
- if (restart || remove_mem.count(mem->name))
- return 0;
-
- if (memwr.at(mem->name).empty() && meminit.at(mem->name).empty()) {
- log("Removing memory %s.%s with no write ports or init data.\n", log_id(module), log_id(mem));
- remove_mem.insert(mem->name);
- return 1;
- }
-
- return 0;
- }
-};
-
struct OptMemPass : public Pass {
OptMemPass() : Pass("opt_mem", "optimize memories") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -106,7 +35,7 @@ struct OptMemPass : public Pass {
log("This pass performs various optimizations on memories in the design.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing OPT_MEM pass (optimize memories).\n");
@@ -122,15 +51,11 @@ struct OptMemPass : public Pass {
int total_count = 0;
for (auto module : design->selected_modules()) {
- while (1) {
- int cnt = 0;
- OptMemWorker worker(module);
- for (auto &it : module->memories)
- if (module->selected(it.second))
- cnt += worker.run(it.second);
- if (!cnt && !worker.restart)
- break;
- total_count += cnt;
+ for (auto &mem : Mem::get_selected_memories(module)) {
+ if (mem.wr_ports.empty() && mem.inits.empty()) {
+ mem.remove();
+ total_count++;
+ }
}
}
diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc
index d845926fc..9086943dc 100644
--- a/passes/opt/opt_merge.cc
+++ b/passes/opt/opt_merge.cc
@@ -173,9 +173,7 @@ struct OptMergeWorker
for (const auto &it : cell1->connections_) {
if (cell1->output(it.first)) {
- if (it.first == ID::Q && (cell1->type.begins_with("$dff") || cell1->type.begins_with("$dlatch") ||
- cell1->type.begins_with("$_DFF") || cell1->type.begins_with("$_DLATCH") || cell1->type.begins_with("$_SR_") ||
- cell1->type.in(ID($adff), ID($sr), ID($ff), ID($_FF_)))) {
+ if (it.first == ID::Q && RTLIL::builtin_ff_cell_types().count(cell1->type)) {
// For the 'Q' output of state elements,
// use the (* init *) attribute value
auto &sig1 = conn1[it.first];
@@ -298,9 +296,7 @@ struct OptMergeWorker
module->connect(RTLIL::SigSig(it.second, other_sig));
assign_map.add(it.second, other_sig);
- if (it.first == ID::Q && (cell->type.begins_with("$dff") || cell->type.begins_with("$dlatch") ||
- cell->type.begins_with("$_DFF") || cell->type.begins_with("$_DLATCH") || cell->type.begins_with("$_SR_") ||
- cell->type.in(ID($adff), ID($sr), ID($ff), ID($_FF_)))) {
+ if (it.first == ID::Q && RTLIL::builtin_ff_cell_types().count(cell->type)) {
for (auto c : it.second.chunks()) {
auto jt = c.wire->attributes.find(ID::init);
if (jt == c.wire->attributes.end())
@@ -326,7 +322,7 @@ struct OptMergeWorker
struct OptMergePass : public Pass {
OptMergePass() : Pass("opt_merge", "consolidate identical cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -342,7 +338,7 @@ struct OptMergePass : public Pass {
log(" Operate on all cell types, not just built-in types.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing OPT_MERGE pass (detect identical cells).\n");
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
index d076addae..67b283e11 100644
--- a/passes/opt/opt_muxtree.cc
+++ b/passes/opt/opt_muxtree.cc
@@ -473,7 +473,7 @@ struct OptMuxtreeWorker
struct OptMuxtreePass : public Pass {
OptMuxtreePass() : Pass("opt_muxtree", "eliminate dead trees in multiplexer trees") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -486,7 +486,7 @@ struct OptMuxtreePass : public Pass {
log("This pass only operates on completely selected modules without processes.\n");
log("\n");
}
- void execute(vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing OPT_MUXTREE pass (detect dead branches in mux trees).\n");
extra_args(args, 1, design);
diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc
index f640f50a0..28de9ceb6 100644
--- a/passes/opt/opt_reduce.cc
+++ b/passes/opt/opt_reduce.cc
@@ -332,7 +332,7 @@ struct OptReduceWorker
struct OptReducePass : public Pass {
OptReducePass() : Pass("opt_reduce", "simplify large MUXes and AND/OR gates") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -353,7 +353,7 @@ struct OptReducePass : public Pass {
log(" alias for -fine\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool do_fine = false;
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
deleted file mode 100644
index 81326a417..000000000
--- a/passes/opt/opt_rmdff.cc
+++ /dev/null
@@ -1,711 +0,0 @@
-/*
- * yosys -- Yosys Open SYnthesis Suite
- *
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-#include "kernel/log.h"
-#include "kernel/register.h"
-#include "kernel/rtlil.h"
-#include "kernel/satgen.h"
-#include "kernel/sigtools.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-USING_YOSYS_NAMESPACE
-PRIVATE_NAMESPACE_BEGIN
-
-SigMap assign_map, dff_init_map;
-SigSet<RTLIL::Cell*> mux_drivers;
-dict<SigBit, RTLIL::Cell*> bit2driver;
-dict<SigBit, pool<SigBit>> init_attributes;
-
-bool keepdc;
-bool sat;
-
-void remove_init_attr(SigSpec sig)
-{
- for (auto bit : assign_map(sig))
- if (init_attributes.count(bit))
- for (auto wbit : init_attributes.at(bit))
- wbit.wire->attributes.at(ID::init)[wbit.offset] = State::Sx;
-}
-
-bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
-{
- SigSpec sig_set, sig_clr;
- State pol_set, pol_clr;
-
- if (cell->hasPort(ID::S))
- sig_set = cell->getPort(ID::S);
-
- if (cell->hasPort(ID::R))
- sig_clr = cell->getPort(ID::R);
-
- if (cell->hasPort(ID::SET))
- sig_set = cell->getPort(ID::SET);
-
- if (cell->hasPort(ID::CLR))
- sig_clr = cell->getPort(ID::CLR);
-
- log_assert(GetSize(sig_set) == GetSize(sig_clr));
-
- if (cell->type.begins_with("$_DFFSR_")) {
- pol_set = cell->type[9] == 'P' ? State::S1 : State::S0;
- pol_clr = cell->type[10] == 'P' ? State::S1 : State::S0;
- } else
- if (cell->type.begins_with("$_DLATCHSR_")) {
- pol_set = cell->type[12] == 'P' ? State::S1 : State::S0;
- pol_clr = cell->type[13] == 'P' ? State::S1 : State::S0;
- } else
- if (cell->type.in(ID($dffsr), ID($dlatchsr))) {
- pol_set = cell->parameters[ID::SET_POLARITY].as_bool() ? State::S1 : State::S0;
- pol_clr = cell->parameters[ID::CLR_POLARITY].as_bool() ? State::S1 : State::S0;
- } else
- log_abort();
-
- State npol_set = pol_set == State::S0 ? State::S1 : State::S0;
- State npol_clr = pol_clr == State::S0 ? State::S1 : State::S0;
-
- SigSpec sig_d = cell->getPort(ID::D);
- SigSpec sig_q = cell->getPort(ID::Q);
-
- bool did_something = false;
- bool proper_sr = false;
- bool used_pol_set = false;
- bool used_pol_clr = false;
- bool hasreset = false;
- Const reset_val;
- SigSpec sig_reset;
-
- for (int i = 0; i < GetSize(sig_set); i++)
- {
- SigBit s = sig_set[i], c = sig_clr[i];
-
- if (s != npol_set || c != npol_clr)
- hasreset = true;
-
- if (s == pol_set || c == pol_clr)
- {
- log("Constantly %s Q bit %s for SR cell %s (%s) from module %s.\n",
- s == pol_set ? "set" : "cleared", log_signal(sig_q[i]),
- log_id(cell), log_id(cell->type), log_id(mod));
-
- remove_init_attr(sig_q[i]);
- mod->connect(sig_q[i], s == pol_set ? State::S1 : State::S0);
- sig_set.remove(i);
- sig_clr.remove(i);
- sig_d.remove(i);
- sig_q.remove(i--);
- did_something = true;
- continue;
- }
- if (sig_reset.empty() && s.wire != nullptr) sig_reset = s;
- if (sig_reset.empty() && c.wire != nullptr) sig_reset = c;
-
- if (s.wire != nullptr && s != sig_reset) proper_sr = true;
- if (c.wire != nullptr && c != sig_reset) proper_sr = true;
-
- if ((s.wire == nullptr) != (c.wire == nullptr)) {
- if (s.wire != nullptr) used_pol_set = true;
- if (c.wire != nullptr) used_pol_clr = true;
- reset_val.bits.push_back(c.wire == nullptr ? State::S1 : State::S0);
- } else
- proper_sr = true;
- }
-
- if (!hasreset)
- proper_sr = false;
-
- if (GetSize(sig_set) == 0)
- {
- log("Removing %s (%s) from module %s.\n", log_id(cell), log_id(cell->type), log_id(mod));
- mod->remove(cell);
- return true;
- }
-
- if (cell->type.in(ID($dffsr), ID($dlatchsr)))
- {
- cell->setParam(ID::WIDTH, GetSize(sig_d));
- cell->setPort(ID::SET, sig_set);
- cell->setPort(ID::CLR, sig_clr);
- cell->setPort(ID::D, sig_d);
- cell->setPort(ID::Q, sig_q);
- }
- else
- {
- cell->setPort(ID::S, sig_set);
- cell->setPort(ID::R, sig_clr);
- cell->setPort(ID::D, sig_d);
- cell->setPort(ID::Q, sig_q);
- }
-
- if (proper_sr)
- return did_something;
-
- if (used_pol_set && used_pol_clr && pol_set != pol_clr)
- return did_something;
-
- if (cell->type == ID($dlatchsr))
- return did_something;
-
- State unified_pol = used_pol_set ? pol_set : pol_clr;
-
- if (cell->type == ID($dffsr))
- {
- if (hasreset)
- {
- log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), "$adff", log_id(mod));
-
- cell->type = ID($adff);
- cell->setParam(ID::ARST_POLARITY, unified_pol);
- cell->setParam(ID::ARST_VALUE, reset_val);
- cell->setPort(ID::ARST, sig_reset);
-
- cell->unsetParam(ID::SET_POLARITY);
- cell->unsetParam(ID::CLR_POLARITY);
- cell->unsetPort(ID::SET);
- cell->unsetPort(ID::CLR);
- }
- else
- {
- log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), "$dff", log_id(mod));
-
- cell->type = ID($dff);
- cell->unsetParam(ID::SET_POLARITY);
- cell->unsetParam(ID::CLR_POLARITY);
- cell->unsetPort(ID::SET);
- cell->unsetPort(ID::CLR);
- }
-
- return true;
- }
-
- if (!hasreset)
- {
- IdString new_type;
-
- if (cell->type.begins_with("$_DFFSR_"))
- new_type = stringf("$_DFF_%c_", cell->type[8]);
- else if (cell->type.begins_with("$_DLATCHSR_"))
- new_type = stringf("$_DLATCH_%c_", cell->type[11]);
- else
- log_abort();
-
- log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), log_id(new_type), log_id(mod));
-
- cell->type = new_type;
- cell->unsetPort(ID::S);
- cell->unsetPort(ID::R);
-
- return true;
- }
-
- return did_something;
-}
-
-bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
-{
- SigSpec sig_e;
- State on_state, off_state;
-
- if (dlatch->type == ID($dlatch)) {
- sig_e = assign_map(dlatch->getPort(ID::EN));
- on_state = dlatch->getParam(ID::EN_POLARITY).as_bool() ? State::S1 : State::S0;
- off_state = dlatch->getParam(ID::EN_POLARITY).as_bool() ? State::S0 : State::S1;
- } else
- if (dlatch->type == ID($_DLATCH_P_)) {
- sig_e = assign_map(dlatch->getPort(ID::E));
- on_state = State::S1;
- off_state = State::S0;
- } else
- if (dlatch->type == ID($_DLATCH_N_)) {
- sig_e = assign_map(dlatch->getPort(ID::E));
- on_state = State::S0;
- off_state = State::S1;
- } else
- log_abort();
-
- if (sig_e == off_state)
- {
- RTLIL::Const val_init;
- for (auto bit : dff_init_map(dlatch->getPort(ID::Q)))
- val_init.bits.push_back(bit.wire == NULL ? bit.data : State::Sx);
- mod->connect(dlatch->getPort(ID::Q), val_init);
- goto delete_dlatch;
- }
-
- if (sig_e == on_state)
- {
- mod->connect(dlatch->getPort(ID::Q), dlatch->getPort(ID::D));
- goto delete_dlatch;
- }
-
- return false;
-
-delete_dlatch:
- log("Removing %s (%s) from module %s.\n", log_id(dlatch), log_id(dlatch->type), log_id(mod));
- remove_init_attr(dlatch->getPort(ID::Q));
- mod->remove(dlatch);
- return true;
-}
-
-bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
-{
- RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r, sig_e;
- RTLIL::Const val_cp, val_rp, val_rv, val_ep;
-
- if (dff->type == ID($_FF_)) {
- sig_d = dff->getPort(ID::D);
- sig_q = dff->getPort(ID::Q);
- }
- else if (dff->type == ID($_DFF_N_) || dff->type == ID($_DFF_P_)) {
- sig_d = dff->getPort(ID::D);
- sig_q = dff->getPort(ID::Q);
- sig_c = dff->getPort(ID::C);
- val_cp = RTLIL::Const(dff->type == ID($_DFF_P_), 1);
- }
- else if (dff->type.begins_with("$_DFF_") && dff->type.compare(9, 1, "_") == 0 &&
- (dff->type[6] == 'N' || dff->type[6] == 'P') &&
- (dff->type[7] == 'N' || dff->type[7] == 'P') &&
- (dff->type[8] == '0' || dff->type[8] == '1')) {
- sig_d = dff->getPort(ID::D);
- sig_q = dff->getPort(ID::Q);
- sig_c = dff->getPort(ID::C);
- sig_r = dff->getPort(ID::R);
- val_cp = RTLIL::Const(dff->type[6] == 'P', 1);
- val_rp = RTLIL::Const(dff->type[7] == 'P', 1);
- val_rv = RTLIL::Const(dff->type[8] == '1', 1);
- }
- else if (dff->type.begins_with("$_DFFE_") && dff->type.compare(9, 1, "_") == 0 &&
- (dff->type[7] == 'N' || dff->type[7] == 'P') &&
- (dff->type[8] == 'N' || dff->type[8] == 'P')) {
- sig_d = dff->getPort(ID::D);
- sig_q = dff->getPort(ID::Q);
- sig_c = dff->getPort(ID::C);
- sig_e = dff->getPort(ID::E);
- val_cp = RTLIL::Const(dff->type[7] == 'P', 1);
- val_ep = RTLIL::Const(dff->type[8] == 'P', 1);
- }
- else if (dff->type == ID($ff)) {
- sig_d = dff->getPort(ID::D);
- sig_q = dff->getPort(ID::Q);
- }
- else if (dff->type == ID($dff)) {
- sig_d = dff->getPort(ID::D);
- sig_q = dff->getPort(ID::Q);
- sig_c = dff->getPort(ID::CLK);
- val_cp = RTLIL::Const(dff->parameters[ID::CLK_POLARITY].as_bool(), 1);
- }
- else if (dff->type == ID($dffe)) {
- sig_e = dff->getPort(ID::EN);
- sig_d = dff->getPort(ID::D);
- sig_q = dff->getPort(ID::Q);
- sig_c = dff->getPort(ID::CLK);
- val_cp = RTLIL::Const(dff->parameters[ID::CLK_POLARITY].as_bool(), 1);
- val_ep = RTLIL::Const(dff->parameters[ID::EN_POLARITY].as_bool(), 1);
- }
- else if (dff->type == ID($adff)) {
- sig_d = dff->getPort(ID::D);
- sig_q = dff->getPort(ID::Q);
- sig_c = dff->getPort(ID::CLK);
- sig_r = dff->getPort(ID::ARST);
- val_cp = RTLIL::Const(dff->parameters[ID::CLK_POLARITY].as_bool(), 1);
- val_rp = RTLIL::Const(dff->parameters[ID::ARST_POLARITY].as_bool(), 1);
- val_rv = dff->parameters[ID::ARST_VALUE];
- }
- else
- log_abort();
-
- assign_map.apply(sig_d);
- assign_map.apply(sig_q);
- assign_map.apply(sig_c);
- assign_map.apply(sig_r);
-
- bool has_init = false;
- RTLIL::Const val_init;
- for (auto bit : dff_init_map(sig_q).to_sigbit_vector()) {
- if (bit.wire == NULL || keepdc)
- has_init = true;
- val_init.bits.push_back(bit.wire == NULL ? bit.data : RTLIL::State::Sx);
- }
-
- if (dff->type.in(ID($ff), ID($dff)) && mux_drivers.has(sig_d)) {
- std::set<RTLIL::Cell*> muxes;
- mux_drivers.find(sig_d, muxes);
- for (auto mux : muxes) {
- RTLIL::SigSpec sig_a = assign_map(mux->getPort(ID::A));
- RTLIL::SigSpec sig_b = assign_map(mux->getPort(ID::B));
- if (sig_a == sig_q && sig_b.is_fully_const() && (!has_init || val_init == sig_b.as_const())) {
- mod->connect(sig_q, sig_b);
- goto delete_dff;
- }
- if (sig_b == sig_q && sig_a.is_fully_const() && (!has_init || val_init == sig_a.as_const())) {
- mod->connect(sig_q, sig_a);
- goto delete_dff;
- }
- }
- }
-
- // If clock is driven by a constant and (i) no reset signal
- // (ii) Q has no initial value
- // (iii) initial value is same as reset value
- if (!sig_c.empty() && sig_c.is_fully_const() && (!sig_r.size() || !has_init || val_init == val_rv)) {
- if (val_rv.bits.size() == 0)
- val_rv = val_init;
- // Q is permanently reset value or initial value
- mod->connect(sig_q, val_rv);
- goto delete_dff;
- }
-
- // If D is fully undefined and reset signal present and (i) Q has no initial value
- // (ii) initial value is same as reset value
- if (sig_d.is_fully_undef() && sig_r.size() && (!has_init || val_init == val_rv)) {
- // Q is permanently reset value
- mod->connect(sig_q, val_rv);
- goto delete_dff;
- }
-
- // If D is fully undefined and no reset signal and Q has an initial value
- if (sig_d.is_fully_undef() && !sig_r.size() && has_init) {
- // Q is permanently initial value
- mod->connect(sig_q, val_init);
- goto delete_dff;
- }
-
- // If D is fully constant and (i) no reset signal
- // (ii) reset value is same as constant D
- // and (a) has no initial value
- // (b) initial value same as constant D
- if (sig_d.is_fully_const() && (!sig_r.size() || val_rv == sig_d.as_const()) && (!has_init || val_init == sig_d.as_const())) {
- // Q is permanently D
- mod->connect(sig_q, sig_d);
- goto delete_dff;
- }
-
- // If D input is same as Q output and (i) no reset signal
- // (ii) no initial signal
- // (iii) initial value is same as reset value
- if (sig_d == sig_q && (sig_r.empty() || !has_init || val_init == val_rv)) {
- // Q is permanently reset value or initial value
- if (sig_r.size())
- mod->connect(sig_q, val_rv);
- else if (has_init)
- mod->connect(sig_q, val_init);
- goto delete_dff;
- }
-
- // If reset signal is present, and is fully constant
- if (!sig_r.empty() && sig_r.is_fully_const())
- {
- // If reset value is permanently active or if reset is undefined
- if (sig_r == val_rp || sig_r.is_fully_undef()) {
- // Q is permanently reset value
- mod->connect(sig_q, val_rv);
- goto delete_dff;
- }
-
- log("Removing unused reset from %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
-
- if (dff->type == ID($adff)) {
- dff->type = ID($dff);
- dff->unsetPort(ID::ARST);
- dff->unsetParam(ID::ARST_POLARITY);
- dff->unsetParam(ID::ARST_VALUE);
- return true;
- }
-
- log_assert(dff->type.begins_with("$_DFF_"));
- dff->type = stringf("$_DFF_%c_", + dff->type[6]);
- dff->unsetPort(ID::R);
- }
-
- // If enable signal is present, and is fully constant
- if (!sig_e.empty() && sig_e.is_fully_const())
- {
- // If enable value is permanently inactive
- if (sig_e != val_ep) {
- // Q is permanently initial value
- mod->connect(sig_q, val_init);
- goto delete_dff;
- }
-
- log("Removing unused enable from %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
-
- if (dff->type == ID($dffe)) {
- dff->type = ID($dff);
- dff->unsetPort(ID::EN);
- dff->unsetParam(ID::EN_POLARITY);
- return true;
- }
-
- log_assert(dff->type.begins_with("$_DFFE_"));
- dff->type = stringf("$_DFF_%c_", + dff->type[7]);
- dff->unsetPort(ID::E);
- }
-
- if (sat && has_init && (!sig_r.size() || val_init == val_rv))
- {
- bool removed_sigbits = false;
-
- ezSatPtr ez;
- SatGen satgen(ez.get(), &assign_map);
- pool<Cell*> sat_cells;
-
- std::function<void(Cell*)> sat_import_cell = [&](Cell *c) {
- if (!sat_cells.insert(c).second)
- return;
- if (!satgen.importCell(c))
- return;
- for (auto &conn : c->connections()) {
- if (!c->input(conn.first))
- continue;
- for (auto bit : assign_map(conn.second))
- if (bit2driver.count(bit))
- sat_import_cell(bit2driver.at(bit));
- }
- };
-
- // For each register bit, try to prove that it cannot change from the initial value. If so, remove it
- for (int position = 0; position < GetSize(sig_d); position += 1) {
- RTLIL::SigBit q_sigbit = sig_q[position];
- RTLIL::SigBit d_sigbit = sig_d[position];
-
- if ((!q_sigbit.wire) || (!d_sigbit.wire))
- continue;
-
- if (!bit2driver.count(d_sigbit))
- continue;
-
- sat_import_cell(bit2driver.at(d_sigbit));
-
- RTLIL::State sigbit_init_val = val_init[position];
- if (sigbit_init_val != State::S0 && sigbit_init_val != State::S1)
- continue;
-
- int init_sat_pi = satgen.importSigSpec(sigbit_init_val).front();
- int q_sat_pi = satgen.importSigBit(q_sigbit);
- int d_sat_pi = satgen.importSigBit(d_sigbit);
-
- // Try to find out whether the register bit can change under some circumstances
- bool counter_example_found = ez->solve(ez->IFF(q_sat_pi, init_sat_pi), ez->NOT(ez->IFF(d_sat_pi, init_sat_pi)));
-
- // If the register bit cannot change, we can replace it with a constant
- if (!counter_example_found)
- {
- log("Setting constant %d-bit at position %d on %s (%s) from module %s.\n", sigbit_init_val ? 1 : 0,
- position, log_id(dff), log_id(dff->type), log_id(mod));
-
- SigSpec tmp = dff->getPort(ID::D);
- tmp[position] = sigbit_init_val;
- dff->setPort(ID::D, tmp);
-
- removed_sigbits = true;
- }
- }
-
- if (removed_sigbits) {
- handle_dff(mod, dff);
- return true;
- }
- }
-
-
- return false;
-
-delete_dff:
- log("Removing %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
- remove_init_attr(dff->getPort(ID::Q));
- mod->remove(dff);
-
- for (auto &entry : bit2driver)
- if (entry.second == dff)
- bit2driver.erase(entry.first);
-
- return true;
-}
-
-struct OptRmdffPass : public Pass {
- OptRmdffPass() : Pass("opt_rmdff", "remove DFFs with constant inputs") { }
- void help() YS_OVERRIDE
- {
- // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
- log("\n");
- log(" opt_rmdff [-keepdc] [-sat] [selection]\n");
- log("\n");
- log("This pass identifies flip-flops with constant inputs and replaces them with\n");
- log("a constant driver.\n");
- log("\n");
- log(" -sat\n");
- log(" additionally invoke SAT solver to detect and remove flip-flops (with \n");
- log(" non-constant inputs) that can also be replaced with a constant driver\n");
- log("\n");
- }
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
- {
- int total_count = 0, total_initdrv = 0;
- log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
-
- keepdc = false;
- sat = false;
-
- size_t argidx;
- for (argidx = 1; argidx < args.size(); argidx++) {
- if (args[argidx] == "-keepdc") {
- keepdc = true;
- continue;
- }
- if (args[argidx] == "-sat") {
- sat = true;
- continue;
- }
- break;
- }
- extra_args(args, argidx, design);
-
- for (auto module : design->selected_modules()) {
- pool<SigBit> driven_bits;
- dict<SigBit, State> init_bits;
-
- assign_map.set(module);
- dff_init_map.set(module);
- mux_drivers.clear();
- bit2driver.clear();
- init_attributes.clear();
-
- for (auto wire : module->wires())
- {
- if (wire->attributes.count(ID::init) != 0) {
- Const initval = wire->attributes.at(ID::init);
- for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++)
- if (initval[i] == State::S0 || initval[i] == State::S1)
- dff_init_map.add(SigBit(wire, i), initval[i]);
- for (int i = 0; i < GetSize(wire); i++) {
- SigBit wire_bit(wire, i), mapped_bit = assign_map(wire_bit);
- if (mapped_bit.wire) {
- init_attributes[mapped_bit].insert(wire_bit);
- if (i < GetSize(initval))
- init_bits[mapped_bit] = initval[i];
- }
- }
- }
-
- if (wire->port_input) {
- for (auto bit : assign_map(wire))
- driven_bits.insert(bit);
- }
- }
-
- std::vector<RTLIL::IdString> dff_list;
- std::vector<RTLIL::IdString> dffsr_list;
- std::vector<RTLIL::IdString> dlatch_list;
- for (auto cell : module->cells())
- {
- for (auto &conn : cell->connections()) {
- bool is_output = cell->output(conn.first);
- if (is_output || !cell->known())
- for (auto bit : assign_map(conn.second)) {
- if (is_output)
- bit2driver[bit] = cell;
- driven_bits.insert(bit);
- }
- }
-
- if (cell->type.in(ID($mux), ID($pmux))) {
- if (cell->getPort(ID::A).size() == cell->getPort(ID::B).size())
- mux_drivers.insert(assign_map(cell->getPort(ID::Y)), cell);
- continue;
- }
-
- if (!design->selected(module, cell))
- continue;
-
- if (cell->type.in(ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
- ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_), ID($dffsr),
- ID($_DLATCHSR_NNN_), ID($_DLATCHSR_NNP_), ID($_DLATCHSR_NPN_), ID($_DLATCHSR_NPP_),
- ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_), ID($dlatchsr)))
- dffsr_list.push_back(cell->name);
-
- if (cell->type.in(ID($_FF_), ID($_DFF_N_), ID($_DFF_P_),
- ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
- ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_),
- ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_),
- ID($ff), ID($dff), ID($dffe), ID($adff)))
- dff_list.push_back(cell->name);
-
- if (cell->type.in(ID($dlatch), ID($_DLATCH_P_), ID($_DLATCH_N_)))
- dlatch_list.push_back(cell->name);
- }
-
- for (auto &id : dffsr_list) {
- if (module->cell(id) != nullptr &&
- handle_dffsr(module, module->cells_[id]))
- total_count++;
- }
-
- for (auto &id : dff_list) {
- if (module->cell(id) != nullptr &&
- handle_dff(module, module->cells_[id]))
- total_count++;
- }
-
- for (auto &id : dlatch_list) {
- if (module->cell(id) != nullptr &&
- handle_dlatch(module, module->cells_[id]))
- total_count++;
- }
-
- SigSpec const_init_sigs;
-
- for (auto bit : init_bits)
- if (!driven_bits.count(bit.first))
- const_init_sigs.append(bit.first);
-
- const_init_sigs.sort_and_unify();
-
- for (SigSpec sig : const_init_sigs.chunks())
- {
- Const val;
-
- for (auto bit : sig)
- val.bits.push_back(init_bits.at(bit));
-
- log("Promoting init spec %s = %s to constant driver in module %s.\n",
- log_signal(sig), log_signal(val), log_id(module));
-
- module->connect(sig, val);
- remove_init_attr(sig);
- total_initdrv++;
- }
- }
-
- assign_map.clear();
- mux_drivers.clear();
- bit2driver.clear();
- init_attributes.clear();
-
- if (total_count || total_initdrv)
- design->scratchpad_set_bool("opt.did_something", true);
-
- if (total_initdrv)
- log("Promoted %d init specs to constant drivers.\n", total_initdrv);
-
- if (total_count)
- log("Replaced %d DFF cells.\n", total_count);
- }
-} OptRmdffPass;
-
-PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc
index cbace7bac..53296699c 100644
--- a/passes/opt/opt_share.cc
+++ b/passes/opt/opt_share.cc
@@ -30,8 +30,6 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-SigMap assign_map;
-
struct OpMuxConn {
RTLIL::SigSpec sig;
RTLIL::Cell *mux;
@@ -157,9 +155,9 @@ bool decode_port_signed(RTLIL::Cell *cell, RTLIL::IdString port_name)
return false;
}
-ExtSigSpec decode_port(RTLIL::Cell *cell, RTLIL::IdString port_name, SigMap *sigmap)
+ExtSigSpec decode_port(RTLIL::Cell *cell, RTLIL::IdString port_name, const SigMap &sigmap)
{
- auto sig = (*sigmap)(cell->getPort(port_name));
+ auto sig = sigmap(cell->getPort(port_name));
RTLIL::SigSpec sign = decode_port_sign(cell, port_name);
RTLIL::IdString semantics = decode_port_semantics(cell, port_name);
@@ -169,7 +167,7 @@ ExtSigSpec decode_port(RTLIL::Cell *cell, RTLIL::IdString port_name, SigMap *sig
return ExtSigSpec(sig, sign, is_signed, semantics);
}
-void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<OpMuxConn> &ports, const ExtSigSpec &operand)
+void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<OpMuxConn> &ports, const ExtSigSpec &operand, const SigMap &sigmap)
{
std::vector<ExtSigSpec> muxed_operands;
int max_width = 0;
@@ -177,10 +175,10 @@ void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<
auto op = p.op;
RTLIL::IdString muxed_port_name = ID::A;
- if (decode_port(op, ID::A, &assign_map) == operand)
+ if (decode_port(op, ID::A, sigmap) == operand)
muxed_port_name = ID::B;
- auto operand = decode_port(op, muxed_port_name, &assign_map);
+ auto operand = decode_port(op, muxed_port_name, sigmap);
if (operand.sig.size() > max_width)
max_width = operand.sig.size();
@@ -190,11 +188,13 @@ void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<
auto shared_op = ports[0].op;
if (std::any_of(muxed_operands.begin(), muxed_operands.end(), [&](ExtSigSpec &op) { return op.sign != muxed_operands[0].sign; }))
- max_width = std::max(max_width, shared_op->getParam(ID::Y_WIDTH).as_int());
-
+ max_width = std::max(max_width, shared_op->getParam(ID::Y_WIDTH).as_int());
- for (auto &operand : muxed_operands)
+ for (auto &operand : muxed_operands) {
operand.sig.extend_u0(max_width, operand.is_signed);
+ if (operand.sign != muxed_operands[0].sign)
+ operand = ExtSigSpec(module->Neg(NEW_ID, operand.sig, operand.is_signed));
+ }
for (const auto& p : ports) {
auto op = p.op;
@@ -203,61 +203,58 @@ void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<
module->remove(op);
}
- for (auto &muxed_op : muxed_operands)
- if (muxed_op.sign != muxed_operands[0].sign)
- muxed_op = ExtSigSpec(module->Neg(NEW_ID, muxed_op.sig, muxed_op.is_signed));
-
- RTLIL::SigSpec mux_y = mux->getPort(ID::Y);
RTLIL::SigSpec mux_a = mux->getPort(ID::A);
RTLIL::SigSpec mux_b = mux->getPort(ID::B);
RTLIL::SigSpec mux_s = mux->getPort(ID::S);
+ int conn_width = ports[0].sig.size();
+ int conn_mux_offset = ports[0].mux_port_offset;
+ int conn_op_offset = ports[0].op_outsig_offset;
+
RTLIL::SigSpec shared_pmux_a = RTLIL::Const(RTLIL::State::Sx, max_width);
RTLIL::SigSpec shared_pmux_b;
RTLIL::SigSpec shared_pmux_s;
- int conn_width = ports[0].sig.size();
- int conn_offset = ports[0].mux_port_offset;
-
- shared_op->setPort(ID::Y, shared_op->getPort(ID::Y).extract(0, conn_width));
+ // Make a new wire to avoid false equivalence with whatever the former shared output was connected to.
+ Wire *new_out = module->addWire(NEW_ID, conn_op_offset + conn_width);
+ SigSpec new_sig_out = SigSpec(new_out, conn_op_offset, conn_width);
- if (mux->type == ID($pmux)) {
- shared_pmux_s = RTLIL::SigSpec();
-
- for (const auto &p : ports) {
+ for (int i = 0; i < GetSize(ports); i++) {
+ auto &p = ports[i];
+ auto &op = muxed_operands[i];
+ if (p.mux_port_id == GetSize(mux_s)) {
+ shared_pmux_a = op.sig;
+ mux_a.replace(conn_mux_offset, new_sig_out);
+ } else {
shared_pmux_s.append(mux_s[p.mux_port_id]);
- mux_b.replace(p.mux_port_id * mux_a.size() + conn_offset, shared_op->getPort(ID::Y));
+ shared_pmux_b.append(op.sig);
+ mux_b.replace(p.mux_port_id * mux_a.size() + conn_mux_offset, new_sig_out);
}
- } else {
- shared_pmux_s = RTLIL::SigSpec{mux_s, module->Not(NEW_ID, mux_s)};
- mux_a.replace(conn_offset, shared_op->getPort(ID::Y));
- mux_b.replace(conn_offset, shared_op->getPort(ID::Y));
}
mux->setPort(ID::A, mux_a);
mux->setPort(ID::B, mux_b);
- mux->setPort(ID::Y, mux_y);
mux->setPort(ID::S, mux_s);
- for (const auto &op : muxed_operands)
- shared_pmux_b.append(op.sig);
-
- auto mux_to_oper = module->Pmux(NEW_ID, shared_pmux_a, shared_pmux_b, shared_pmux_s);
+ SigSpec mux_to_oper;
+ if (GetSize(shared_pmux_s) == 1) {
+ mux_to_oper = module->Mux(NEW_ID, shared_pmux_a, shared_pmux_b, shared_pmux_s);
+ } else {
+ mux_to_oper = module->Pmux(NEW_ID, shared_pmux_a, shared_pmux_b, shared_pmux_s);
+ }
if (shared_op->type.in(ID($alu))) {
- RTLIL::SigSpec alu_x = shared_op->getPort(ID::X);
- RTLIL::SigSpec alu_co = shared_op->getPort(ID::CO);
-
- shared_op->setPort(ID::X, alu_x.extract(0, conn_width));
- shared_op->setPort(ID::CO, alu_co.extract(0, conn_width));
+ shared_op->setPort(ID::X, module->addWire(NEW_ID, GetSize(new_sig_out)));
+ shared_op->setPort(ID::CO, module->addWire(NEW_ID, GetSize(new_sig_out)));
}
bool is_fine = shared_op->type.in(FINE_BITWISE_OPS);
+ shared_op->setPort(ID::Y, new_out);
if (!is_fine)
- shared_op->setParam(ID::Y_WIDTH, conn_width);
+ shared_op->setParam(ID::Y_WIDTH, GetSize(new_out));
- if (decode_port(shared_op, ID::A, &assign_map) == operand) {
+ if (decode_port(shared_op, ID::A, sigmap) == operand) {
shared_op->setPort(ID::B, mux_to_oper);
if (!is_fine)
shared_op->setParam(ID::B_WIDTH, max_width);
@@ -275,17 +272,7 @@ typedef struct {
} merged_op_t;
-template <typename T> void remove_val(std::vector<T> &v, const std::vector<T> &vals)
-{
- auto val_iter = vals.rbegin();
- for (auto i = v.rbegin(); i != v.rend(); ++i)
- if ((val_iter != vals.rend()) && (*i == *val_iter)) {
- v.erase(i.base() - 1);
- ++val_iter;
- }
-}
-
-void check_muxed_operands(std::vector<const OpMuxConn *> &ports, const ExtSigSpec &shared_operand)
+void check_muxed_operands(std::vector<const OpMuxConn *> &ports, const ExtSigSpec &shared_operand, const SigMap &sigmap)
{
auto it = ports.begin();
ExtSigSpec seed;
@@ -295,11 +282,11 @@ void check_muxed_operands(std::vector<const OpMuxConn *> &ports, const ExtSigSpe
auto op = p->op;
RTLIL::IdString muxed_port_name = ID::A;
- if (decode_port(op, ID::A, &assign_map) == shared_operand) {
+ if (decode_port(op, ID::A, sigmap) == shared_operand) {
muxed_port_name = ID::B;
}
- auto operand = decode_port(op, muxed_port_name, &assign_map);
+ auto operand = decode_port(op, muxed_port_name, sigmap);
if (seed.empty())
seed = operand;
@@ -312,7 +299,7 @@ void check_muxed_operands(std::vector<const OpMuxConn *> &ports, const ExtSigSpe
}
}
-ExtSigSpec find_shared_operand(const OpMuxConn* seed, std::vector<const OpMuxConn *> &ports, const std::map<ExtSigSpec, std::set<RTLIL::Cell *>> &operand_to_users)
+ExtSigSpec find_shared_operand(const OpMuxConn* seed, std::vector<const OpMuxConn *> &ports, const std::map<ExtSigSpec, std::set<RTLIL::Cell *>> &operand_to_users, const SigMap &sigmap)
{
std::set<RTLIL::Cell *> ops_using_operand;
std::set<RTLIL::Cell *> ops_set;
@@ -324,7 +311,7 @@ ExtSigSpec find_shared_operand(const OpMuxConn* seed, std::vector<const OpMuxCon
auto op_a = seed->op;
for (RTLIL::IdString port_name : {ID::A, ID::B}) {
- oper = decode_port(op_a, port_name, &assign_map);
+ oper = decode_port(op_a, port_name, sigmap);
auto operand_users = operand_to_users.at(oper);
if (operand_users.size() == 1)
@@ -345,135 +332,9 @@ ExtSigSpec find_shared_operand(const OpMuxConn* seed, std::vector<const OpMuxCon
return ExtSigSpec();
}
-dict<RTLIL::SigSpec, OpMuxConn> find_valid_op_mux_conns(RTLIL::Module *module, dict<RTLIL::SigBit, RTLIL::SigSpec> &op_outbit_to_outsig,
- dict<RTLIL::SigSpec, RTLIL::Cell *> outsig_to_operator,
- dict<RTLIL::SigBit, RTLIL::SigSpec> &op_aux_to_outsig)
-{
- dict<RTLIL::SigSpec, int> op_outsig_user_track;
- dict<RTLIL::SigSpec, OpMuxConn> op_mux_conn_map;
-
- std::function<void(RTLIL::SigSpec)> remove_outsig = [&](RTLIL::SigSpec outsig) {
- for (auto op_outbit : outsig)
- op_outbit_to_outsig.erase(op_outbit);
-
- if (op_mux_conn_map.count(outsig))
- op_mux_conn_map.erase(outsig);
- };
-
- std::function<void(RTLIL::SigBit)> remove_outsig_from_aux_bit = [&](RTLIL::SigBit auxbit) {
- auto aux_outsig = op_aux_to_outsig.at(auxbit);
- auto op = outsig_to_operator.at(aux_outsig);
- auto op_outsig = assign_map(op->getPort(ID::Y));
- remove_outsig(op_outsig);
-
- for (auto aux_outbit : aux_outsig)
- op_aux_to_outsig.erase(aux_outbit);
- };
-
- std::function<void(RTLIL::Cell *)> find_op_mux_conns = [&](RTLIL::Cell *mux) {
- RTLIL::SigSpec sig;
- int mux_port_size;
-
- if (mux->type.in(ID($mux), ID($_MUX_))) {
- mux_port_size = mux->getPort(ID::A).size();
- sig = RTLIL::SigSpec{mux->getPort(ID::B), mux->getPort(ID::A)};
- } else {
- mux_port_size = mux->getPort(ID::A).size();
- sig = mux->getPort(ID::B);
- }
-
- auto mux_insig = assign_map(sig);
-
- for (int i = 0; i < mux_insig.size(); ++i) {
- if (op_aux_to_outsig.count(mux_insig[i])) {
- remove_outsig_from_aux_bit(mux_insig[i]);
- continue;
- }
-
- if (!op_outbit_to_outsig.count(mux_insig[i]))
- continue;
-
- auto op_outsig = op_outbit_to_outsig.at(mux_insig[i]);
-
- if (op_mux_conn_map.count(op_outsig)) {
- remove_outsig(op_outsig);
- continue;
- }
-
- int mux_port_id = i / mux_port_size;
- int mux_port_offset = i % mux_port_size;
-
- int op_outsig_offset;
- for (op_outsig_offset = 0; op_outsig[op_outsig_offset] != mux_insig[i]; ++op_outsig_offset)
- ;
-
- int j = op_outsig_offset;
- do {
- if (!op_outbit_to_outsig.count(mux_insig[i]))
- break;
-
- if (op_outbit_to_outsig.at(mux_insig[i]) != op_outsig)
- break;
-
- ++i;
- ++j;
- } while ((i / mux_port_size == mux_port_id) && (j < op_outsig.size()));
-
- int op_conn_width = j - op_outsig_offset;
- OpMuxConn inp = {
- op_outsig.extract(op_outsig_offset, op_conn_width),
- mux,
- outsig_to_operator.at(op_outsig),
- mux_port_id,
- mux_port_offset,
- op_outsig_offset,
- };
-
- op_mux_conn_map[op_outsig] = inp;
-
- --i;
- }
- };
-
- std::function<void(RTLIL::SigSpec)> remove_connected_ops = [&](RTLIL::SigSpec sig) {
- auto mux_insig = assign_map(sig);
- for (auto outbit : mux_insig) {
- if (op_aux_to_outsig.count(outbit)) {
- remove_outsig_from_aux_bit(outbit);
- continue;
- }
-
- if (!op_outbit_to_outsig.count(outbit))
- continue;
-
- remove_outsig(op_outbit_to_outsig.at(outbit));
- }
- };
-
- for (auto cell : module->cells()) {
- if (cell->type.in(ID($mux), ID($_MUX_), ID($pmux))) {
- remove_connected_ops(cell->getPort(ID::S));
- find_op_mux_conns(cell);
- } else {
- for (auto &conn : cell->connections())
- if (cell->input(conn.first))
- remove_connected_ops(conn.second);
- }
- }
-
- for (auto w : module->wires()) {
- if (!w->port_output)
- continue;
-
- remove_connected_ops(w);
- }
-
- return op_mux_conn_map;
-}
-
struct OptSharePass : public Pass {
OptSharePass() : Pass("opt_share", "merge mutually exclusive cells of the same type that share an input signal") {}
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -488,44 +349,53 @@ struct OptSharePass : public Pass {
log("multiplexing its output to multiplexing the non-shared input signals.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing OPT_SHARE pass.\n");
extra_args(args, 1, design);
for (auto module : design->selected_modules()) {
- assign_map.clear();
- assign_map.set(module);
+ SigMap sigmap(module);
+
+ dict<RTLIL::SigBit, int> bit_users;
+
+ for (auto cell : module->cells())
+ for (auto conn : cell->connections())
+ for (auto bit : conn.second)
+ bit_users[sigmap(bit)]++;
+
+ for (auto wire : module->wires())
+ if (wire->port_id != 0)
+ for (auto bit : SigSpec(wire))
+ bit_users[sigmap(bit)]++;
std::map<ExtSigSpec, std::set<RTLIL::Cell *>> operand_to_users;
- dict<RTLIL::SigSpec, RTLIL::Cell *> outsig_to_operator;
- dict<RTLIL::SigBit, RTLIL::SigSpec> op_outbit_to_outsig;
- dict<RTLIL::SigBit, RTLIL::SigSpec> op_aux_to_outsig;
+ dict<RTLIL::SigBit, std::pair<RTLIL::Cell *, int>> op_outbit_to_outsig;
bool any_shared_operands = false;
- std::vector<ExtSigSpec> op_insigs;
- for (auto cell : module->cells()) {
+ for (auto cell : module->selected_cells()) {
if (!cell_supported(cell))
continue;
+ bool skip = false;
if (cell->type == ID($alu)) {
for (RTLIL::IdString port_name : {ID::X, ID::CO}) {
- auto mux_insig = assign_map(cell->getPort(port_name));
- outsig_to_operator[mux_insig] = cell;
- for (auto outbit : mux_insig)
- op_aux_to_outsig[outbit] = mux_insig;
+ for (auto outbit : sigmap(cell->getPort(port_name)))
+ if (bit_users[outbit] > 1)
+ skip = true;
}
}
- auto mux_insig = assign_map(cell->getPort(ID::Y));
- outsig_to_operator[mux_insig] = cell;
- for (auto outbit : mux_insig)
- op_outbit_to_outsig[outbit] = mux_insig;
+ if (skip)
+ continue;
+
+ auto mux_insig = sigmap(cell->getPort(ID::Y));
+ for (int i = 0; i < GetSize(mux_insig); i++)
+ op_outbit_to_outsig[mux_insig[i]] = std::make_pair(cell, i);
for (RTLIL::IdString port_name : {ID::A, ID::B}) {
- auto op_insig = decode_port(cell, port_name, &assign_map);
- op_insigs.push_back(op_insig);
+ auto op_insig = decode_port(cell, port_name, sigmap);
operand_to_users[op_insig].insert(cell);
if (operand_to_users[op_insig].size() > 1)
any_shared_operands = true;
@@ -537,34 +407,79 @@ struct OptSharePass : public Pass {
// Operator outputs need to be exclusively connected to the $mux inputs in order to be mergeable. Hence we count to
// how many points are operator output bits connected.
- dict<RTLIL::SigSpec, OpMuxConn> op_mux_conn_map =
- find_valid_op_mux_conns(module, op_outbit_to_outsig, outsig_to_operator, op_aux_to_outsig);
+ std::vector<merged_op_t> merged_ops;
- // Group op connections connected to same ports of the same $mux. Sort them in ascending order of their port offset
- dict<RTLIL::Cell*, std::vector<std::set<OpMuxConn>>> mux_port_op_conns;
- for (auto& val: op_mux_conn_map) {
- OpMuxConn p = val.second;
- auto& mux_port_conns = mux_port_op_conns[p.mux];
+ for (auto mux : module->selected_cells()) {
+ if (!mux->type.in(ID($mux), ID($_MUX_), ID($pmux)))
+ continue;
- if (mux_port_conns.size() == 0) {
- int mux_port_num;
+ int mux_port_size = GetSize(mux->getPort(ID::A));
+ int mux_port_num = GetSize(mux->getPort(ID::S)) + 1;
- if (p.mux->type.in(ID($mux), ID($_MUX_)))
- mux_port_num = 2;
- else
- mux_port_num = p.mux->getPort(ID::S).size();
+ RTLIL::SigSpec mux_insig = sigmap(RTLIL::SigSpec{mux->getPort(ID::B), mux->getPort(ID::A)});
+ std::vector<std::set<OpMuxConn>> mux_port_conns(mux_port_num);
+ int found = 0;
- mux_port_conns.resize(mux_port_num);
- }
+ for (int mux_port_id = 0; mux_port_id < mux_port_num; mux_port_id++) {
+ SigSpec mux_insig;
+ if (mux_port_id == mux_port_num - 1) {
+ mux_insig = sigmap(mux->getPort(ID::A));
+ } else {
+ mux_insig = sigmap(mux->getPort(ID::B).extract(mux_port_id * mux_port_size, mux_port_size));
+ }
- mux_port_conns[p.mux_port_id].insert(p);
- }
+ for (int mux_port_offset = 0; mux_port_offset < mux_port_size; ++mux_port_offset) {
+ if (!op_outbit_to_outsig.count(mux_insig[mux_port_offset]))
+ continue;
- std::vector<merged_op_t> merged_ops;
- for (auto& val: mux_port_op_conns) {
+ RTLIL::Cell *cell;
+ int op_outsig_offset;
+ std::tie(cell, op_outsig_offset) = op_outbit_to_outsig.at(mux_insig[mux_port_offset]);
+ SigSpec op_outsig = sigmap(cell->getPort(ID::Y));
+ int op_outsig_size = GetSize(op_outsig);
+ int op_conn_width = 0;
+
+ while (mux_port_offset + op_conn_width < mux_port_size &&
+ op_outsig_offset + op_conn_width < op_outsig_size &&
+ mux_insig[mux_port_offset + op_conn_width] == op_outsig[op_outsig_offset + op_conn_width])
+ op_conn_width++;
+
+ log_assert(op_conn_width >= 1);
+
+ bool skip = false;
+ for (int i = 0; i < op_outsig_size; i++) {
+ int expected = 1;
+ if (i >= op_outsig_offset && i < op_outsig_offset + op_conn_width)
+ expected = 2;
+ if (bit_users[op_outsig[i]] != expected)
+ skip = true;
+ }
+ if (skip) {
+ mux_port_offset += op_conn_width;
+ mux_port_offset--;
+ continue;
+ }
+
+ OpMuxConn inp = {
+ op_outsig.extract(op_outsig_offset, op_conn_width),
+ mux,
+ cell,
+ mux_port_id,
+ mux_port_offset,
+ op_outsig_offset,
+ };
+
+ mux_port_conns[mux_port_id].insert(inp);
+
+ mux_port_offset += op_conn_width;
+ mux_port_offset--;
- RTLIL::Cell* cell = val.first;
- auto &mux_port_conns = val.second;
+ found++;
+ }
+ }
+
+ if (found < 2)
+ continue;
const OpMuxConn *seed = NULL;
@@ -612,12 +527,12 @@ struct OptSharePass : public Pass {
continue;
// Filter mergeable connections whose ops share an operand with seed connection's op
- auto shared_operand = find_shared_operand(seed, mergeable_conns, operand_to_users);
+ auto shared_operand = find_shared_operand(seed, mergeable_conns, operand_to_users, sigmap);
if (shared_operand.empty())
continue;
- check_muxed_operands(mergeable_conns, shared_operand);
+ check_muxed_operands(mergeable_conns, shared_operand, sigmap);
if (mergeable_conns.size() < 2)
continue;
@@ -631,7 +546,7 @@ struct OptSharePass : public Pass {
seed = NULL;
- merged_ops.push_back(merged_op_t{cell, merged_ports, shared_operand});
+ merged_ops.push_back(merged_op_t{mux, merged_ports, shared_operand});
design->scratchpad_set_bool("opt.did_something", true);
}
@@ -647,7 +562,7 @@ struct OptSharePass : public Pass {
log(" %s\n", log_id(op.op));
log("\n");
- merge_operators(module, shared.mux, shared.ports, shared.shared_operand);
+ merge_operators(module, shared.mux, shared.ports, shared.shared_operand, sigmap);
}
}
}
diff --git a/passes/opt/pmux2shiftx.cc b/passes/opt/pmux2shiftx.cc
index 11b80b6b3..f3b1fd377 100644
--- a/passes/opt/pmux2shiftx.cc
+++ b/passes/opt/pmux2shiftx.cc
@@ -19,6 +19,7 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
+#include "kernel/ffinit.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -30,7 +31,7 @@ struct OnehotDatabase
bool verbose = false;
bool initialized = false;
- pool<SigBit> init_ones;
+ FfInitVals initvals;
dict<SigSpec, pool<SigSpec>> sig_sources_db;
dict<SigSpec, bool> sig_onehot_cache;
pool<SigSpec> recursion_guard;
@@ -44,30 +45,20 @@ struct OnehotDatabase
log_assert(!initialized);
initialized = true;
- for (auto wire : module->wires())
- {
- auto it = wire->attributes.find(ID::init);
- if (it == wire->attributes.end())
- continue;
-
- auto &val = it->second;
- int width = std::max(GetSize(wire), GetSize(val));
-
- for (int i = 0; i < width; i++)
- if (val[i] == State::S1)
- init_ones.insert(sigmap(SigBit(wire, i)));
- }
+ initvals.set(&sigmap, module);
for (auto cell : module->cells())
{
vector<SigSpec> inputs;
SigSpec output;
- if (cell->type.in(ID($adff), ID($dff), ID($dffe), ID($dlatch), ID($ff)))
+ if (cell->type.in(ID($adff), ID($adffe), ID($dff), ID($dffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($ff)))
{
output = cell->getPort(ID::Q);
- if (cell->type == ID($adff))
+ if (cell->type.in(ID($adff), ID($adffe), ID($adlatch)))
inputs.push_back(cell->getParam(ID::ARST_VALUE));
+ if (cell->type.in(ID($sdff), ID($sdffe), ID($sdffce)))
+ inputs.push_back(cell->getParam(ID::SRST_VALUE));
inputs.push_back(cell->getPort(ID::D));
}
@@ -117,7 +108,7 @@ struct OnehotDatabase
bool found_init_ones = false;
for (auto bit : sig) {
- if (init_ones.count(bit)) {
+ if (initvals(bit) == State::S1) {
if (found_init_ones) {
if (verbose)
log("%*s - non-onehot init value\n", indent, "");
@@ -198,7 +189,7 @@ struct OnehotDatabase
struct Pmux2ShiftxPass : public Pass {
Pmux2ShiftxPass() : Pass("pmux2shiftx", "transform $pmux cells to $shiftx cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -225,7 +216,7 @@ struct Pmux2ShiftxPass : public Pass {
log(" disable $sub inference for \"range decoders\"\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
int min_density = 50;
int min_choices = 3;
@@ -737,7 +728,7 @@ struct Pmux2ShiftxPass : public Pass {
struct OnehotPass : public Pass {
OnehotPass() : Pass("onehot", "optimize $eq cells for onehot signals") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -749,7 +740,7 @@ struct OnehotPass : public Pass {
log(" verbose output\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool verbose = false;
bool verbose_onehot = false;
diff --git a/passes/opt/rmports.cc b/passes/opt/rmports.cc
index 32363dd68..99a2a61c8 100644
--- a/passes/opt/rmports.cc
+++ b/passes/opt/rmports.cc
@@ -28,7 +28,7 @@ PRIVATE_NAMESPACE_BEGIN
struct RmportsPassPass : public Pass {
RmportsPassPass() : Pass("rmports", "remove module ports with no connections") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -39,7 +39,7 @@ struct RmportsPassPass : public Pass {
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing RMPORTS pass (remove ports with no connections).\n");
diff --git a/passes/opt/share.cc b/passes/opt/share.cc
index 988253edf..f7848e01d 100644
--- a/passes/opt/share.cc
+++ b/passes/opt/share.cc
@@ -1444,7 +1444,7 @@ struct ShareWorker
struct SharePass : public Pass {
SharePass() : Pass("share", "perform sat-based resource sharing") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1476,7 +1476,7 @@ struct SharePass : public Pass {
log(" Only perform the first N merges, then stop. This is useful for debugging.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
ShareWorkerConfig config;
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index f60f2f8a8..a216f36d4 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -20,6 +20,7 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/modtools.h"
+#include "kernel/ffinit.h"
USING_YOSYS_NAMESPACE
@@ -39,7 +40,8 @@ struct WreduceConfig
ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt),
ID($add), ID($sub), ID($mul), // ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow),
ID($mux), ID($pmux),
- ID($dff), ID($adff)
+ ID($dff), ID($dffe), ID($adff), ID($adffe), ID($sdff), ID($sdffe), ID($sdffce),
+ ID($dlatch), ID($adlatch),
});
}
};
@@ -53,8 +55,7 @@ struct WreduceWorker
std::set<Cell*, IdString::compare_ptr_by_name<Cell>> work_queue_cells;
std::set<SigBit> work_queue_bits;
pool<SigBit> keep_bits;
- dict<SigBit, State> init_bits;
- pool<SigBit> remove_init_bits;
+ FfInitVals initvals;
WreduceWorker(WreduceConfig *config, Module *module) :
config(config), module(module), mi(module) { }
@@ -143,8 +144,8 @@ struct WreduceWorker
SigSpec sig_d = mi.sigmap(cell->getPort(ID::D));
SigSpec sig_q = mi.sigmap(cell->getPort(ID::Q));
- bool is_adff = (cell->type == ID($adff));
- Const initval, arst_value;
+ bool has_reset = false;
+ Const initval = initvals(sig_q), rst_value;
int width_before = GetSize(sig_q);
@@ -152,35 +153,31 @@ struct WreduceWorker
return;
if (cell->parameters.count(ID::ARST_VALUE)) {
- arst_value = cell->parameters[ID::ARST_VALUE];
+ rst_value = cell->parameters[ID::ARST_VALUE];
+ has_reset = true;
+ } else if (cell->parameters.count(ID::SRST_VALUE)) {
+ rst_value = cell->parameters[ID::SRST_VALUE];
+ has_reset = true;
}
bool zero_ext = sig_d[GetSize(sig_d)-1] == State::S0;
bool sign_ext = !zero_ext;
- for (int i = 0; i < GetSize(sig_q); i++) {
- SigBit bit = sig_q[i];
- if (init_bits.count(bit))
- initval.bits.push_back(init_bits.at(bit));
- else
- initval.bits.push_back(State::Sx);
- }
-
for (int i = GetSize(sig_q)-1; i >= 0; i--)
{
if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx) &&
- (!is_adff || i >= GetSize(arst_value) || arst_value[i] == State::S0 || arst_value[i] == State::Sx)) {
+ (!has_reset || i >= GetSize(rst_value) || rst_value[i] == State::S0 || rst_value[i] == State::Sx)) {
module->connect(sig_q[i], State::S0);
- remove_init_bits.insert(sig_q[i]);
+ initvals.remove_init(sig_q[i]);
sig_d.remove(i);
sig_q.remove(i);
continue;
}
if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1] &&
- (!is_adff || i >= GetSize(arst_value) || arst_value[i] == arst_value[i-1])) {
+ (!has_reset || i >= GetSize(rst_value) || rst_value[i] == rst_value[i-1])) {
module->connect(sig_q[i], sig_q[i-1]);
- remove_init_bits.insert(sig_q[i]);
+ initvals.remove_init(sig_q[i]);
sig_d.remove(i);
sig_q.remove(i);
continue;
@@ -190,7 +187,7 @@ struct WreduceWorker
if (info == nullptr)
return;
if (!info->is_output && GetSize(info->ports) == 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) {
- remove_init_bits.insert(sig_q[i]);
+ initvals.remove_init(sig_q[i]);
sig_d.remove(i);
sig_q.remove(i);
zero_ext = false;
@@ -221,8 +218,11 @@ struct WreduceWorker
// Narrow ARST_VALUE parameter to new size.
if (cell->parameters.count(ID::ARST_VALUE)) {
- arst_value.bits.resize(GetSize(sig_q));
- cell->setParam(ID::ARST_VALUE, arst_value);
+ rst_value.bits.resize(GetSize(sig_q));
+ cell->setParam(ID::ARST_VALUE, rst_value);
+ } else if (cell->parameters.count(ID::SRST_VALUE)) {
+ rst_value.bits.resize(GetSize(sig_q));
+ cell->setParam(ID::SRST_VALUE, rst_value);
}
cell->setPort(ID::D, sig_d);
@@ -272,7 +272,7 @@ struct WreduceWorker
if (cell->type.in(ID($mux), ID($pmux)))
return run_cell_mux(cell);
- if (cell->type.in(ID($dff), ID($adff)))
+ if (cell->type.in(ID($dff), ID($dffe), ID($adff), ID($adffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch)))
return run_cell_dff(cell);
SigSpec sig = mi.sigmap(cell->getPort(ID::Y));
@@ -401,18 +401,12 @@ struct WreduceWorker
{
// create a copy as mi.sigmap will be updated as we process the module
SigMap init_attr_sigmap = mi.sigmap;
+ initvals.set(&init_attr_sigmap, module);
for (auto w : module->wires()) {
if (w->get_bool_attribute(ID::keep))
for (auto bit : mi.sigmap(w))
keep_bits.insert(bit);
- if (w->attributes.count(ID::init)) {
- Const initval = w->attributes.at(ID::init);
- SigSpec initsig = init_attr_sigmap(w);
- int width = std::min(GetSize(initval), GetSize(initsig));
- for (int i = 0; i < width; i++)
- init_bits[initsig[i]] = initval[i];
- }
}
for (auto c : module->selected_cells())
@@ -461,28 +455,12 @@ struct WreduceWorker
module->connect(nw, SigSpec(w).extract(0, GetSize(nw)));
module->swap_names(w, nw);
}
-
- if (!remove_init_bits.empty()) {
- for (auto w : module->wires()) {
- if (w->attributes.count(ID::init)) {
- Const initval = w->attributes.at(ID::init);
- Const new_initval(State::Sx, GetSize(w));
- SigSpec initsig = init_attr_sigmap(w);
- int width = std::min(GetSize(initval), GetSize(initsig));
- for (int i = 0; i < width; i++) {
- if (!remove_init_bits.count(initsig[i]))
- new_initval[i] = initval[i];
- }
- w->attributes.at(ID::init) = new_initval;
- }
- }
- }
}
};
struct WreducePass : public Pass {
WreducePass() : Pass("wreduce", "reduce the word size of operations if possible") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -505,7 +483,7 @@ struct WreducePass : public Pass {
log(" Do not optimize explicit don't-care values.\n");
log("\n");
}
- void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, Design *design) override
{
WreduceConfig config;
bool opt_memx = false;
diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc
index 1a57bef7d..c6bbc386a 100644
--- a/passes/pmgen/Makefile.inc
+++ b/passes/pmgen/Makefile.inc
@@ -36,7 +36,6 @@ $(eval $(call add_extra_objs,passes/pmgen/peepopt_pm.h))
PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg
PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg
-PEEPOPT_PATTERN += passes/pmgen/peepopt_dffmux.pmg
passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
$(P) mkdir -p passes/pmgen && $(PYTHON_EXECUTABLE) $< -o $@ -p peepopt $(filter-out $<,$^)
diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc
index f16cc4a0b..c46f5d58f 100644
--- a/passes/pmgen/ice40_dsp.cc
+++ b/passes/pmgen/ice40_dsp.cc
@@ -31,15 +31,15 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul));
- log_debug("ffA: %s %s %s\n", log_id(st.ffA, "--"), log_id(st.ffAholdmux, "--"), log_id(st.ffArstmux, "--"));
- log_debug("ffB: %s %s %s\n", log_id(st.ffB, "--"), log_id(st.ffBholdmux, "--"), log_id(st.ffBrstmux, "--"));
- log_debug("ffCD: %s %s\n", log_id(st.ffCD, "--"), log_id(st.ffCDholdmux, "--"));
+ log_debug("ffA: %s\n", log_id(st.ffA, "--"));
+ log_debug("ffB: %s\n", log_id(st.ffB, "--"));
+ log_debug("ffCD: %s\n", log_id(st.ffCD, "--"));
log_debug("mul: %s\n", log_id(st.mul, "--"));
log_debug("ffFJKG: %s\n", log_id(st.ffFJKG, "--"));
log_debug("ffH: %s\n", log_id(st.ffH, "--"));
log_debug("add: %s\n", log_id(st.add, "--"));
log_debug("mux: %s\n", log_id(st.mux, "--"));
- log_debug("ffO: %s %s %s\n", log_id(st.ffO, "--"), log_id(st.ffOholdmux, "--"), log_id(st.ffOrstmux, "--"));
+ log_debug("ffO: %s\n", log_id(st.ffO, "--"));
log_debug("\n");
if (GetSize(st.sigA) > 16) {
@@ -97,16 +97,16 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setParam(ID(D_REG), st.ffCD ? State::S1 : State::S0);
SigSpec AHOLD, BHOLD, CDHOLD;
- if (st.ffAholdmux)
- AHOLD = st.ffAholdpol ? st.ffAholdmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffAholdmux->getPort(ID::S));
+ if (st.ffA && st.ffA->hasPort(ID::EN))
+ AHOLD = st.ffA->getParam(ID::EN_POLARITY).as_bool() ? pm.module->Not(NEW_ID, st.ffA->getPort(ID::EN)) : st.ffA->getPort(ID::EN);
else
AHOLD = State::S0;
- if (st.ffBholdmux)
- BHOLD = st.ffBholdpol ? st.ffBholdmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffBholdmux->getPort(ID::S));
+ if (st.ffB && st.ffB->hasPort(ID::EN))
+ BHOLD = st.ffB->getParam(ID::EN_POLARITY).as_bool() ? pm.module->Not(NEW_ID, st.ffB->getPort(ID::EN)) : st.ffB->getPort(ID::EN);
else
BHOLD = State::S0;
- if (st.ffCDholdmux)
- CDHOLD = st.ffCDholdpol ? st.ffCDholdmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffCDholdmux->getPort(ID::S));
+ if (st.ffCD && st.ffCD->hasPort(ID::EN))
+ CDHOLD = st.ffCD->getParam(ID::EN_POLARITY).as_bool() ? pm.module->Not(NEW_ID, st.ffCD->getPort(ID::EN)) : st.ffCD->getPort(ID::EN);
else
CDHOLD = State::S0;
cell->setPort(ID(AHOLD), AHOLD);
@@ -115,12 +115,12 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setPort(ID(DHOLD), CDHOLD);
SigSpec IRSTTOP, IRSTBOT;
- if (st.ffArstmux)
- IRSTTOP = st.ffArstpol ? st.ffArstmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffArstmux->getPort(ID::S));
+ if (st.ffA && st.ffA->hasPort(ID::ARST))
+ IRSTTOP = st.ffA->getParam(ID::ARST_POLARITY).as_bool() ? st.ffA->getPort(ID::ARST) : pm.module->Not(NEW_ID, st.ffA->getPort(ID::ARST));
else
IRSTTOP = State::S0;
- if (st.ffBrstmux)
- IRSTBOT = st.ffBrstpol ? st.ffBrstmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffBrstmux->getPort(ID::S));
+ if (st.ffB && st.ffB->hasPort(ID::ARST))
+ IRSTBOT = st.ffB->getParam(ID::ARST_POLARITY).as_bool() ? st.ffB->getPort(ID::ARST) : pm.module->Not(NEW_ID, st.ffB->getPort(ID::ARST));
else
IRSTBOT = State::S0;
cell->setPort(ID(IRSTTOP), IRSTTOP);
@@ -207,16 +207,16 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
}
SigSpec OHOLD;
- if (st.ffOholdmux)
- OHOLD = st.ffOholdpol ? st.ffOholdmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffOholdmux->getPort(ID::S));
+ if (st.ffO && st.ffO->hasPort(ID::EN))
+ OHOLD = st.ffO->getParam(ID::EN_POLARITY).as_bool() ? pm.module->Not(NEW_ID, st.ffO->getPort(ID::EN)) : st.ffO->getPort(ID::EN);
else
OHOLD = State::S0;
cell->setPort(ID(OHOLDTOP), OHOLD);
cell->setPort(ID(OHOLDBOT), OHOLD);
SigSpec ORST;
- if (st.ffOrstmux)
- ORST = st.ffOrstpol ? st.ffOrstmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffOrstmux->getPort(ID::S));
+ if (st.ffO && st.ffO->hasPort(ID::ARST))
+ ORST = st.ffO->getParam(ID::ARST_POLARITY).as_bool() ? st.ffO->getPort(ID::ARST) : pm.module->Not(NEW_ID, st.ffO->getPort(ID::ARST));
else
ORST = State::S0;
cell->setPort(ID(ORSTTOP), ORST);
@@ -228,6 +228,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
acc_reset = st.mux->getPort(ID::S);
else
acc_reset = pm.module->Not(NEW_ID, st.mux->getPort(ID::S));
+ } else if (st.ffO && st.ffO->hasPort(ID::SRST)) {
+ acc_reset = st.ffO->getParam(ID::SRST_POLARITY).as_bool() ? st.ffO->getPort(ID::SRST) : pm.module->Not(NEW_ID, st.ffO->getPort(ID::SRST));
}
cell->setPort(ID(OLOADTOP), acc_reset);
cell->setPort(ID(OLOADBOT), acc_reset);
@@ -275,7 +277,7 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
struct Ice40DspPass : public Pass {
Ice40DspPass() : Pass("ice40_dsp", "iCE40: map multipliers") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -294,7 +296,7 @@ struct Ice40DspPass : public Pass {
log("the accumulator to an arbitrary value can be inferred to use the {C,D} input.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing ICE40_DSP pass (map multipliers).\n");
diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg
index 2456a49dc..7a01cbd51 100644
--- a/passes/pmgen/ice40_dsp.pmg
+++ b/passes/pmgen/ice40_dsp.pmg
@@ -6,20 +6,16 @@ state <SigSpec> sigA sigB sigCD sigH sigO
state <Cell*> add mux
state <IdString> addAB muxAB
-state <bool> ffAholdpol ffBholdpol ffCDholdpol ffOholdpol
-state <bool> ffArstpol ffBrstpol ffCDrstpol ffOrstpol
-
-state <Cell*> ffA ffAholdmux ffArstmux ffB ffBholdmux ffBrstmux ffCD ffCDholdmux
-state <Cell*> ffFJKG ffH ffO ffOholdmux ffOrstmux
+state <Cell*> ffA ffB ffCD
+state <Cell*> ffFJKG ffH ffO
// subpattern
+state <bool> argSdff
state <SigSpec> argQ argD
-state <bool> ffholdpol ffrstpol
-state <int> ffoffset
udata <SigSpec> dffD dffQ
udata <SigBit> dffclock
-udata <Cell*> dff dffholdmux dffrstmux
-udata <bool> dffholdpol dffrstpol dffclock_pol
+udata <Cell*> dff
+udata <bool> dffclock_pol
match mul
select mul->type.in($mul, \SB_MAC16)
@@ -64,7 +60,7 @@ code sigA sigB sigH
log_assert(nusers(O.extract_end(i)) <= 1);
endcode
-code argQ ffA ffAholdmux ffArstmux ffAholdpol ffArstpol sigA clock clock_pol
+code argQ ffA sigA clock clock_pol
if (mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool()) {
argQ = sigA;
subpattern(in_dffe);
@@ -72,20 +68,12 @@ code argQ ffA ffAholdmux ffArstmux ffAholdpol ffArstpol sigA clock clock_pol
ffA = dff;
clock = dffclock;
clock_pol = dffclock_pol;
- if (dffrstmux) {
- ffArstmux = dffrstmux;
- ffArstpol = dffrstpol;
- }
- if (dffholdmux) {
- ffAholdmux = dffholdmux;
- ffAholdpol = dffholdpol;
- }
sigA = dffD;
}
}
endcode
-code argQ ffB ffBholdmux ffBrstmux ffBholdpol ffBrstpol sigB clock clock_pol
+code argQ ffB sigB clock clock_pol
if (mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool()) {
argQ = sigB;
subpattern(in_dffe);
@@ -93,47 +81,44 @@ code argQ ffB ffBholdmux ffBrstmux ffBholdpol ffBrstpol sigB clock clock_pol
ffB = dff;
clock = dffclock;
clock_pol = dffclock_pol;
- if (dffrstmux) {
- ffBrstmux = dffrstmux;
- ffBrstpol = dffrstpol;
- }
- if (dffholdmux) {
- ffBholdmux = dffholdmux;
- ffBholdpol = dffholdpol;
- }
sigB = dffD;
}
}
endcode
-code argD ffFJKG sigH clock clock_pol
+code argD argSdff ffFJKG sigH clock clock_pol
if (nusers(sigH) == 2 &&
(mul->type != \SB_MAC16 ||
(!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool()))) {
argD = sigH;
+ argSdff = false;
subpattern(out_dffe);
if (dff) {
// F/J/K/G do not have a CE-like (hold) input
- if (dffholdmux)
+ if (dff->hasPort(\EN))
goto reject_ffFJKG;
// Reset signal of F/J (IRSTTOP) and K/G (IRSTBOT)
// shared with A and B
- if ((ffArstmux != NULL) != (dffrstmux != NULL))
- goto reject_ffFJKG;
- if ((ffBrstmux != NULL) != (dffrstmux != NULL))
- goto reject_ffFJKG;
- if (ffArstmux) {
- if (port(ffArstmux, \S) != port(dffrstmux, \S))
- goto reject_ffFJKG;
- if (ffArstpol != dffrstpol)
+ if (ffA) {
+ if (ffA->hasPort(\ARST) != dff->hasPort(\ARST))
goto reject_ffFJKG;
+ if (ffA->hasPort(\ARST)) {
+ if (port(ffA, \ARST) != port(dff, \ARST))
+ goto reject_ffFJKG;
+ if (param(ffA, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
+ goto reject_ffFJKG;
+ }
}
- if (ffBrstmux) {
- if (port(ffBrstmux, \S) != port(dffrstmux, \S))
- goto reject_ffFJKG;
- if (ffBrstpol != dffrstpol)
+ if (ffB) {
+ if (ffB->hasPort(\ARST) != dff->hasPort(\ARST))
goto reject_ffFJKG;
+ if (ffB->hasPort(\ARST)) {
+ if (port(ffB, \ARST) != port(dff, \ARST))
+ goto reject_ffFJKG;
+ if (param(ffB, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
+ goto reject_ffFJKG;
+ }
}
ffFJKG = dff;
@@ -146,23 +131,24 @@ reject_ffFJKG: ;
}
endcode
-code argD ffH sigH sigO clock clock_pol
+code argD argSdff ffH sigH sigO clock clock_pol
if (ffFJKG && nusers(sigH) == 2 &&
(mul->type != \SB_MAC16 || !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool())) {
argD = sigH;
+ argSdff = false;
subpattern(out_dffe);
if (dff) {
// H does not have a CE-like (hold) input
- if (dffholdmux)
+ if (dff->hasPort(\EN))
goto reject_ffH;
// Reset signal of H (IRSTBOT) shared with B
- if ((ffBrstmux != NULL) != (dffrstmux != NULL))
+ if (ffB->hasPort(\ARST) != dff->hasPort(\ARST))
goto reject_ffH;
- if (ffBrstmux) {
- if (port(ffBrstmux, \S) != port(dffrstmux, \S))
+ if (ffB->hasPort(\ARST)) {
+ if (port(ffB, \ARST) != port(dff, \ARST))
goto reject_ffH;
- if (ffBrstpol != dffrstpol)
+ if (param(ffB, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
goto reject_ffH;
}
@@ -226,7 +212,7 @@ code sigO
sigO = port(mux, \Y);
endcode
-code argD ffO ffOholdmux ffOrstmux ffOholdpol ffOrstpol sigO sigCD clock clock_pol cd_signed o_lo
+code argD argSdff ffO sigO sigCD clock clock_pol cd_signed o_lo
if (mul->type != \SB_MAC16 ||
// Ensure that register is not already used
((param(mul, \TOPOUTPUT_SELECT).as_int() != 1 && param(mul, \BOTOUTPUT_SELECT).as_int() != 1) &&
@@ -238,6 +224,7 @@ code argD ffO ffOholdmux ffOrstmux ffOholdpol ffOrstpol sigO sigCD clock clock_p
// First try entire sigO
if (nusers(sigO) == 2) {
argD = sigO;
+ argSdff = !mux;
subpattern(out_dffe);
}
@@ -245,6 +232,7 @@ code argD ffO ffOholdmux ffOrstmux ffOholdpol ffOrstpol sigO sigCD clock clock_p
if (!dff && GetSize(sigO) > 16) {
argD = sigO.extract(0, 16);
if (nusers(argD) == 2) {
+ argSdff = !mux;
subpattern(out_dffe);
o_lo = dff;
}
@@ -254,14 +242,6 @@ code argD ffO ffOholdmux ffOrstmux ffOholdpol ffOrstpol sigO sigCD clock clock_p
ffO = dff;
clock = dffclock;
clock_pol = dffclock_pol;
- if (dffrstmux) {
- ffOrstmux = dffrstmux;
- ffOrstpol = dffrstpol;
- }
- if (dffholdmux) {
- ffOholdmux = dffholdmux;
- ffOholdpol = dffholdpol;
- }
sigO.replace(sigO.extract(0, GetSize(dffQ)), dffQ);
}
@@ -274,38 +254,43 @@ code argD ffO ffOholdmux ffOrstmux ffOholdpol ffOrstpol sigO sigCD clock clock_p
sigCD = port(mux, muxAB == \B ? \A : \B);
cd_signed = add && param(add, \A_SIGNED).as_bool() && param(add, \B_SIGNED).as_bool();
+ } else if (dff && dff->hasPort(\SRST)) {
+ if (sigCD != sigO)
+ reject;
+ sigCD = param(dff, \SRST_VALUE);
+
+ cd_signed = add && param(add, \A_SIGNED).as_bool() && param(add, \B_SIGNED).as_bool();
}
}
endcode
-code argQ ffCD ffCDholdmux ffCDholdpol ffCDrstpol sigCD clock clock_pol
+code argQ ffCD sigCD clock clock_pol
if (!sigCD.empty() && sigCD != sigO &&
(mul->type != \SB_MAC16 || (!param(mul, \C_REG).as_bool() && !param(mul, \D_REG).as_bool()))) {
argQ = sigCD;
subpattern(in_dffe);
if (dff) {
- if (dffholdmux) {
- ffCDholdmux = dffholdmux;
- ffCDholdpol = dffholdpol;
- }
-
// Reset signal of C (IRSTTOP) and D (IRSTBOT)
// shared with A and B
- if ((ffArstmux != NULL) != (dffrstmux != NULL))
- goto reject_ffCD;
- if ((ffBrstmux != NULL) != (dffrstmux != NULL))
- goto reject_ffCD;
- if (ffArstmux) {
- if (port(ffArstmux, \S) != port(dffrstmux, \S))
- goto reject_ffCD;
- if (ffArstpol != dffrstpol)
+ if (ffA) {
+ if (ffA->hasPort(\ARST) != dff->hasPort(\ARST))
goto reject_ffCD;
+ if (ffA->hasPort(\ARST)) {
+ if (port(ffA, \ARST) != port(dff, \ARST))
+ goto reject_ffCD;
+ if (param(ffA, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
+ goto reject_ffCD;
+ }
}
- if (ffBrstmux) {
- if (port(ffBrstmux, \S) != port(dffrstmux, \S))
- goto reject_ffCD;
- if (ffBrstpol != dffrstpol)
+ if (ffB) {
+ if (ffB->hasPort(\ARST) != dff->hasPort(\ARST))
goto reject_ffCD;
+ if (ffB->hasPort(\ARST)) {
+ if (port(ffB, \ARST) != port(dff, \ARST))
+ goto reject_ffCD;
+ if (param(ffB, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
+ goto reject_ffCD;
+ }
}
ffCD = dff;
@@ -347,7 +332,7 @@ code
endcode
match ff
- select ff->type.in($dff)
+ select ff->type.in($dff, $dffe)
// DSP48E1 does not support clock inversion
select param(ff, \CLK_POLARITY).as_bool()
@@ -357,8 +342,6 @@ match ff
// Check that the rest of argQ is present
filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
-
- set ffoffset offset
endmatch
code argQ argD
@@ -378,72 +361,13 @@ code argQ argD
argD = port(ff, \D);
argQ = Q;
dffD.replace(argQ, argD);
- // Only search for ffrstmux if dffD only
- // has two (ff, ffrstmux) users
- if (nusers(dffD) > 2)
- argD = SigSpec();
}
endcode
-match ffrstmux
- if false /* TODO: ice40 resets are actually async */
-
- if !argD.empty()
- select ffrstmux->type.in($mux)
- index <SigSpec> port(ffrstmux, \Y) === argD
-
- choice <IdString> BA {\B, \A}
- // DSP48E1 only supports reset to zero
- select port(ffrstmux, BA).is_fully_zero()
-
- define <bool> pol (BA == \B)
- set ffrstpol pol
- semioptional
-endmatch
-
-code argD
- if (ffrstmux) {
- dffrstmux = ffrstmux;
- dffrstpol = ffrstpol;
- argD = port(ffrstmux, ffrstpol ? \A : \B);
- dffD.replace(port(ffrstmux, \Y), argD);
-
- // Only search for ffholdmux if argQ has at
- // least 3 users (ff, <upstream>, ffrstmux) and
- // dffD only has two (ff, ffrstmux)
- if (!(nusers(argQ) >= 3 && nusers(dffD) == 2))
- argD = SigSpec();
- }
- else
- dffrstmux = nullptr;
-endcode
-
-match ffholdmux
- if !argD.empty()
- select ffholdmux->type.in($mux)
- index <SigSpec> port(ffholdmux, \Y) === argD
- choice <IdString> BA {\B, \A}
- index <SigSpec> port(ffholdmux, BA) === argQ
- define <bool> pol (BA == \B)
- set ffholdpol pol
- semioptional
-endmatch
-
-code argD
- if (ffholdmux) {
- dffholdmux = ffholdmux;
- dffholdpol = ffholdpol;
- argD = port(ffholdmux, ffholdpol ? \A : \B);
- dffD.replace(port(ffholdmux, \Y), argD);
- }
- else
- dffholdmux = nullptr;
-endcode
-
// #######################
subpattern out_dffe
-arg argD argQ clock clock_pol
+arg argD argSdff argQ clock clock_pol
code
dff = nullptr;
@@ -452,101 +376,19 @@ code
reject;
endcode
-match ffholdmux
- select ffholdmux->type.in($mux)
- // ffholdmux output must have two users: ffholdmux and ff.D
- select nusers(port(ffholdmux, \Y)) == 2
-
- choice <IdString> BA {\B, \A}
- // keep-last-value net must have at least three users: ffholdmux, ff, downstream sink(s)
- select nusers(port(ffholdmux, BA)) >= 3
-
- slice offset GetSize(port(ffholdmux, \Y))
- define <IdString> AB (BA == \B ? \A : \B)
- index <SigBit> port(ffholdmux, AB)[offset] === argD[0]
-
- // Check that the rest of argD is present
- filter GetSize(port(ffholdmux, AB)) >= offset + GetSize(argD)
- filter port(ffholdmux, AB).extract(offset, GetSize(argD)) == argD
-
- set ffoffset offset
- define <bool> pol (BA == \B)
- set ffholdpol pol
-
- semioptional
-endmatch
-
-code argD argQ
- dffholdmux = ffholdmux;
- if (ffholdmux) {
- SigSpec AB = port(ffholdmux, ffholdpol ? \A : \B);
- SigSpec Y = port(ffholdmux, \Y);
- argQ = argD;
- argD.replace(AB, Y);
- argQ.replace(AB, port(ffholdmux, ffholdpol ? \B : \A));
-
- dffholdmux = ffholdmux;
- dffholdpol = ffholdpol;
- }
-endcode
-
-match ffrstmux
- if false /* TODO: ice40 resets are actually async */
-
- select ffrstmux->type.in($mux)
- // ffrstmux output must have two users: ffrstmux and ff.D
- select nusers(port(ffrstmux, \Y)) == 2
-
- choice <IdString> BA {\B, \A}
- // DSP48E1 only supports reset to zero
- select port(ffrstmux, BA).is_fully_zero()
-
- slice offset GetSize(port(ffrstmux, \Y))
- define <IdString> AB (BA == \B ? \A : \B)
- index <SigBit> port(ffrstmux, AB)[offset] === argD[0]
-
- // Check that offset is consistent
- filter !ffholdmux || ffoffset == offset
- // Check that the rest of argD is present
- filter GetSize(port(ffrstmux, AB)) >= offset + GetSize(argD)
- filter port(ffrstmux, AB).extract(offset, GetSize(argD)) == argD
-
- set ffoffset offset
- define <bool> pol (AB == \A)
- set ffrstpol pol
-
- semioptional
-endmatch
-
-code argD argQ
- dffrstmux = ffrstmux;
- if (ffrstmux) {
- SigSpec AB = port(ffrstmux, ffrstpol ? \A : \B);
- SigSpec Y = port(ffrstmux, \Y);
- argD.replace(AB, Y);
-
- dffrstmux = ffrstmux;
- dffrstpol = ffrstpol;
- }
-endcode
-
match ff
- select ff->type.in($dff)
+ select ff->type.in($dff, $dffe, $sdff, $sdffce)
// SB_MAC16 does not support clock inversion
select param(ff, \CLK_POLARITY).as_bool()
slice offset GetSize(port(ff, \D))
index <SigBit> port(ff, \D)[offset] === argD[0]
- // Check that offset is consistent
- filter (!ffholdmux && !ffrstmux) || ffoffset == offset
+ // Only allow sync reset if requested.
+ filter argSdff || ff->type.in($dff, $dffe)
// Check that the rest of argD is present
filter GetSize(port(ff, \D)) >= offset + GetSize(argD)
filter port(ff, \D).extract(offset, GetSize(argD)) == argD
- // Check that FF.Q is connected to CE-mux
- filter !ffholdmux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
-
- set ffoffset offset
endmatch
code argQ
@@ -559,10 +401,8 @@ code argQ
}
SigSpec D = port(ff, \D);
SigSpec Q = port(ff, \Q);
- if (!ffholdmux) {
- argQ = argD;
- argQ.replace(D, Q);
- }
+ argQ = argD;
+ argQ.replace(D, Q);
for (auto c : argQ.chunks()) {
Const init = c.wire->attributes.at(\init, State::Sx);
@@ -575,7 +415,4 @@ code argQ
dffclock = port(ff, \CLK);
dffclock_pol = param(ff, \CLK_POLARITY).as_bool();
}
- // No enable/reset mux possible without flop
- else if (dffholdmux || dffrstmux)
- reject;
endcode
diff --git a/passes/pmgen/ice40_wrapcarry.cc b/passes/pmgen/ice40_wrapcarry.cc
index 97d2008c2..e234906ad 100644
--- a/passes/pmgen/ice40_wrapcarry.cc
+++ b/passes/pmgen/ice40_wrapcarry.cc
@@ -72,7 +72,7 @@ void create_ice40_wrapcarry(ice40_wrapcarry_pm &pm)
struct Ice40WrapCarryPass : public Pass {
Ice40WrapCarryPass() : Pass("ice40_wrapcarry", "iCE40: wrap carries") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -91,7 +91,7 @@ struct Ice40WrapCarryPass : public Pass {
log(" including restoring their attributes.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool unwrap = false;
diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc
index 4379ce1e6..a9c62fcf6 100644
--- a/passes/pmgen/peepopt.cc
+++ b/passes/pmgen/peepopt.cc
@@ -32,7 +32,7 @@ pool<SigBit> rminitbits;
struct PeepoptPass : public Pass {
PeepoptPass() : Pass("peepopt", "collection of peephole optimizers") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -41,7 +41,7 @@ struct PeepoptPass : public Pass {
log("This pass applies a collection of peephole optimizers to the current design.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::string genmode;
@@ -67,8 +67,6 @@ struct PeepoptPass : public Pass {
GENERATE_PATTERN(peepopt_pm, shiftmul);
else if (genmode == "muldiv")
GENERATE_PATTERN(peepopt_pm, muldiv);
- else if (genmode == "dffmux")
- GENERATE_PATTERN(peepopt_pm, dffmux);
else
log_abort();
return;
@@ -106,7 +104,6 @@ struct PeepoptPass : public Pass {
pm.run_shiftmul();
pm.run_muldiv();
- pm.run_dffmux();
for (auto w : module->wires()) {
auto it = w->attributes.find(ID::init);
diff --git a/passes/pmgen/peepopt_dffmux.pmg b/passes/pmgen/peepopt_dffmux.pmg
deleted file mode 100644
index 0069b0570..000000000
--- a/passes/pmgen/peepopt_dffmux.pmg
+++ /dev/null
@@ -1,171 +0,0 @@
-pattern dffmux
-
-state <IdString> cemuxAB rstmuxBA
-state <SigSpec> sigD
-
-match dff
- select dff->type == $dff
- select GetSize(port(dff, \D)) > 1
-endmatch
-
-code sigD
- sigD = port(dff, \D);
-endcode
-
-match rstmux
- select rstmux->type == $mux
- select GetSize(port(rstmux, \Y)) > 1
- index <SigSpec> port(rstmux, \Y) === sigD
- choice <IdString> BA {\B, \A}
- select port(rstmux, BA).is_fully_const()
- set rstmuxBA BA
- semioptional
-endmatch
-
-code sigD
- if (rstmux)
- sigD = port(rstmux, rstmuxBA == \B ? \A : \B);
-endcode
-
-match cemux
- select cemux->type == $mux
- select GetSize(port(cemux, \Y)) > 1
- index <SigSpec> port(cemux, \Y) === sigD
- choice <IdString> AB {\A, \B}
- index <SigSpec> port(cemux, AB) === port(dff, \Q)
- set cemuxAB AB
- semioptional
-endmatch
-
-code
- if (!cemux && !rstmux)
- reject;
-endcode
-
-code
- Const rst;
- SigSpec D;
- if (cemux) {
- D = port(cemux, cemuxAB == \A ? \B : \A);
- if (rstmux)
- rst = port(rstmux, rstmuxBA).as_const();
- else
- rst = Const(State::Sx, GetSize(D));
- }
- else {
- log_assert(rstmux);
- D = port(rstmux, rstmuxBA == \B ? \A : \B);
- rst = port(rstmux, rstmuxBA).as_const();
- }
- SigSpec Q = port(dff, \Q);
- int width = GetSize(D);
-
- SigSpec dffD = dff->getPort(\D);
- SigSpec dffQ = dff->getPort(\Q);
-
- Const initval;
- for (auto b : Q) {
- auto it = initbits.find(b);
- initval.bits.push_back(it == initbits.end() ? State::Sx : it->second);
- }
-
- auto cmpx = [=](State lhs, State rhs) {
- if (lhs == State::Sx || rhs == State::Sx)
- return true;
- return lhs == rhs;
- };
-
- int i = width-1;
- while (i > 1) {
- if (D[i] != D[i-1])
- break;
- if (!cmpx(rst[i], rst[i-1]))
- break;
- if (!cmpx(initval[i], initval[i-1]))
- break;
- if (!cmpx(rst[i], initval[i]))
- break;
- rminitbits.insert(Q[i]);
- module->connect(Q[i], Q[i-1]);
- i--;
- }
- if (i < width-1) {
- did_something = true;
- if (cemux) {
- SigSpec ceA = cemux->getPort(\A);
- SigSpec ceB = cemux->getPort(\B);
- SigSpec ceY = cemux->getPort(\Y);
- ceA.remove(i, width-1-i);
- ceB.remove(i, width-1-i);
- ceY.remove(i, width-1-i);
- cemux->setPort(\A, ceA);
- cemux->setPort(\B, ceB);
- cemux->setPort(\Y, ceY);
- cemux->fixup_parameters();
- blacklist(cemux);
- }
- if (rstmux) {
- SigSpec rstA = rstmux->getPort(\A);
- SigSpec rstB = rstmux->getPort(\B);
- SigSpec rstY = rstmux->getPort(\Y);
- rstA.remove(i, width-1-i);
- rstB.remove(i, width-1-i);
- rstY.remove(i, width-1-i);
- rstmux->setPort(\A, rstA);
- rstmux->setPort(\B, rstB);
- rstmux->setPort(\Y, rstY);
- rstmux->fixup_parameters();
- blacklist(rstmux);
- }
- dffD.remove(i, width-1-i);
- dffQ.remove(i, width-1-i);
- dff->setPort(\D, dffD);
- dff->setPort(\Q, dffQ);
- dff->fixup_parameters();
- blacklist(dff);
-
- log("dffcemux pattern in %s: dff=%s, cemux=%s, rstmux=%s; removed top %d bits.\n", log_id(module), log_id(dff), log_id(cemux, "n/a"), log_id(rstmux, "n/a"), width-1-i);
- width = i+1;
- }
- if (cemux) {
- SigSpec ceA = cemux->getPort(\A);
- SigSpec ceB = cemux->getPort(\B);
- SigSpec ceY = cemux->getPort(\Y);
-
- int count = 0;
- for (int i = width-1; i >= 0; i--) {
- if (D[i].wire)
- continue;
- if (cmpx(rst[i], D[i].data) && cmpx(initval[i], D[i].data)) {
- count++;
- rminitbits.insert(Q[i]);
- module->connect(Q[i], D[i]);
- ceA.remove(i);
- ceB.remove(i);
- ceY.remove(i);
- dffD.remove(i);
- dffQ.remove(i);
- }
- }
- if (count > 0)
- {
- did_something = true;
-
- cemux->setPort(\A, ceA);
- cemux->setPort(\B, ceB);
- cemux->setPort(\Y, ceY);
- cemux->fixup_parameters();
- blacklist(cemux);
-
- dff->setPort(\D, dffD);
- dff->setPort(\Q, dffQ);
- dff->fixup_parameters();
- blacklist(dff);
-
- log("dffcemux pattern in %s: dff=%s, cemux=%s, rstmux=%s; removed %d constant bits.\n", log_id(module), log_id(dff), log_id(cemux), log_id(rstmux, "n/a"), count);
- }
- }
-
- if (did_something)
- accept;
-endcode
diff --git a/passes/pmgen/peepopt_muldiv.pmg b/passes/pmgen/peepopt_muldiv.pmg
index 7cad759d0..a4e232342 100644
--- a/passes/pmgen/peepopt_muldiv.pmg
+++ b/passes/pmgen/peepopt_muldiv.pmg
@@ -1,16 +1,18 @@
pattern muldiv
state <SigSpec> t x y
+state <bool> is_signed
match mul
select mul->type == $mul
select GetSize(port(mul, \A)) + GetSize(port(mul, \B)) <= GetSize(port(mul, \Y))
endmatch
-code t x y
+code t x y is_signed
t = port(mul, \Y);
x = port(mul, \A);
y = port(mul, \B);
+ is_signed = param(mul, \A_SIGNED).as_bool();
branch;
std::swap(x, y);
endcode
@@ -19,6 +21,7 @@ match div
select div->type.in($div)
index <SigSpec> port(div, \A) === t
index <SigSpec> port(div, \B) === x
+ filter param(div, \A_SIGNED).as_bool() == is_signed
endmatch
code
diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg
index d4748ae19..d71fbf744 100644
--- a/passes/pmgen/peepopt_shiftmul.pmg
+++ b/passes/pmgen/peepopt_shiftmul.pmg
@@ -31,22 +31,18 @@ match mul
select mul->type.in($mul)
select port(mul, \A).is_fully_const() || port(mul, \B).is_fully_const()
index <SigSpec> port(mul, \Y) === shamt
+ filter !param(mul, \A_SIGNED).as_bool()
endmatch
code
{
IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B;
- IdString const_factor_signed = const_factor_port == \A ? \A_SIGNED : \B_SIGNED;
Const const_factor_cnst = port(mul, const_factor_port).as_const();
int const_factor = const_factor_cnst.as_int();
if (GetSize(const_factor_cnst) == 0)
reject;
- if (const_factor_cnst.bits[GetSize(const_factor_cnst)-1] != State::S0 &&
- param(mul, const_factor_signed).as_bool())
- reject;
-
if (GetSize(const_factor_cnst) > 20)
reject;
diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py
index df0ffaff2..592a26fa6 100644
--- a/passes/pmgen/pmgen.py
+++ b/passes/pmgen/pmgen.py
@@ -589,7 +589,7 @@ with open(outfile, "w") as f:
if block["type"] in ("match", "code"):
print(" // {}".format(block["src"]), file=f)
- print(" void block_{}(int recursion YS_ATTRIBUTE(unused)) {{".format(index), file=f)
+ print(" void block_{}(int recursion YS_MAYBE_UNUSED) {{".format(index), file=f)
current_pattern, current_subpattern = block["pattern"]
if block["type"] == "final":
@@ -636,17 +636,17 @@ with open(outfile, "w") as f:
for s in sorted(const_st):
t = state_types[current_pattern][s]
if t.endswith("*"):
- print(" {} const &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
+ print(" {} const &{} YS_MAYBE_UNUSED = st_{}.{};".format(t, s, current_pattern, s), file=f)
else:
- print(" const {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
+ print(" const {} &{} YS_MAYBE_UNUSED = st_{}.{};".format(t, s, current_pattern, s), file=f)
for s in sorted(nonconst_st):
t = state_types[current_pattern][s]
- print(" {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
+ print(" {} &{} YS_MAYBE_UNUSED = st_{}.{};".format(t, s, current_pattern, s), file=f)
for u in sorted(udata_types[current_pattern].keys()):
t = udata_types[current_pattern][u]
- print(" {} &{} YS_ATTRIBUTE(unused) = ud_{}.{};".format(t, u, current_pattern, u), file=f)
+ print(" {} &{} YS_MAYBE_UNUSED = ud_{}.{};".format(t, u, current_pattern, u), file=f)
if len(restore_st):
print("", file=f)
@@ -676,7 +676,7 @@ with open(outfile, "w") as f:
print("", file=f)
print("rollback_label:", file=f)
- print(" YS_ATTRIBUTE(unused);", file=f)
+ print(" YS_MAYBE_UNUSED;", file=f)
if len(block["fcode"]):
print("#define accept do { accept_cnt++; on_accept(); } while(0)", file=f)
@@ -684,7 +684,7 @@ with open(outfile, "w") as f:
for line in block["fcode"]:
print(" " + line, file=f)
print("finish_label:", file=f)
- print(" YS_ATTRIBUTE(unused);", file=f)
+ print(" YS_MAYBE_UNUSED;", file=f)
print("#undef accept", file=f)
print("#undef finish", file=f)
@@ -733,13 +733,13 @@ with open(outfile, "w") as f:
valueidx = 1
for item in block["setup"]:
if item[0] == "slice":
- print(" const int &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], valueidx), file=f)
+ print(" const int &{} YS_MAYBE_UNUSED = std::get<{}>(cells[_pmg_idx]);".format(item[1], valueidx), file=f)
valueidx += 1
if item[0] == "choice":
- print(" const {} &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], item[2], valueidx), file=f)
+ print(" const {} &{} YS_MAYBE_UNUSED = std::get<{}>(cells[_pmg_idx]);".format(item[1], item[2], valueidx), file=f)
valueidx += 1
if item[0] == "define":
- print(" const {} &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], item[2], valueidx), file=f)
+ print(" const {} &{} YS_MAYBE_UNUSED = std::get<{}>(cells[_pmg_idx]);".format(item[1], item[2], valueidx), file=f)
valueidx += 1
print(" if (blacklist_cells.count({})) continue;".format(block["cell"]), file=f)
for expr in block["filter"]:
diff --git a/passes/pmgen/test_pmgen.cc b/passes/pmgen/test_pmgen.cc
index 9cfad03ef..7b2938ddf 100644
--- a/passes/pmgen/test_pmgen.cc
+++ b/passes/pmgen/test_pmgen.cc
@@ -118,7 +118,7 @@ void opt_eqpmux(test_pmgen_pm &pm)
struct TestPmgenPass : public Pass {
TestPmgenPass() : Pass("test_pmgen", "test pass for pmgen") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -239,7 +239,7 @@ struct TestPmgenPass : public Pass {
log_cmd_error("Unknown pattern: %s\n", pattern.c_str());
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
if (GetSize(args) > 1)
{
diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc
index f1f4b4206..cf7703d36 100644
--- a/passes/pmgen/xilinx_dsp.cc
+++ b/passes/pmgen/xilinx_dsp.cc
@@ -263,17 +263,17 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm)
log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp));
log_debug("preAdd: %s\n", log_id(st.preAdd, "--"));
- log_debug("ffAD: %s %s %s\n", log_id(st.ffAD, "--"), log_id(st.ffADcemux, "--"), log_id(st.ffADrstmux, "--"));
- log_debug("ffA2: %s %s %s\n", log_id(st.ffA2, "--"), log_id(st.ffA2cemux, "--"), log_id(st.ffA2rstmux, "--"));
- log_debug("ffA1: %s %s %s\n", log_id(st.ffA1, "--"), log_id(st.ffA1cemux, "--"), log_id(st.ffA1rstmux, "--"));
- log_debug("ffB2: %s %s %s\n", log_id(st.ffB2, "--"), log_id(st.ffB2cemux, "--"), log_id(st.ffB2rstmux, "--"));
- log_debug("ffB1: %s %s %s\n", log_id(st.ffB1, "--"), log_id(st.ffB1cemux, "--"), log_id(st.ffB1rstmux, "--"));
- log_debug("ffD: %s %s %s\n", log_id(st.ffD, "--"), log_id(st.ffDcemux, "--"), log_id(st.ffDrstmux, "--"));
+ log_debug("ffAD: %s\n", log_id(st.ffAD, "--"));
+ log_debug("ffA2: %s\n", log_id(st.ffA2, "--"));
+ log_debug("ffA1: %s\n", log_id(st.ffA1, "--"));
+ log_debug("ffB2: %s\n", log_id(st.ffB2, "--"));
+ log_debug("ffB1: %s\n", log_id(st.ffB1, "--"));
+ log_debug("ffD: %s\n", log_id(st.ffD, "--"));
log_debug("dsp: %s\n", log_id(st.dsp, "--"));
- log_debug("ffM: %s %s %s\n", log_id(st.ffM, "--"), log_id(st.ffMcemux, "--"), log_id(st.ffMrstmux, "--"));
+ log_debug("ffM: %s\n", log_id(st.ffM, "--"));
log_debug("postAdd: %s\n", log_id(st.postAdd, "--"));
log_debug("postAddMux: %s\n", log_id(st.postAddMux, "--"));
- log_debug("ffP: %s %s %s\n", log_id(st.ffP, "--"), log_id(st.ffPcemux, "--"), log_id(st.ffPrstmux, "--"));
+ log_debug("ffP: %s\n", log_id(st.ffP, "--"));
log_debug("overflow: %s\n", log_id(st.overflow, "--"));
Cell *cell = st.dsp;
@@ -291,9 +291,10 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm)
cell->setPort(ID(INMODE), Const::from_string("00100"));
if (st.ffAD) {
- if (st.ffADcemux) {
- SigSpec S = st.ffADcemux->getPort(ID::S);
- cell->setPort(ID(CEAD), st.ffADcepol ? S : pm.module->Not(NEW_ID, S));
+ if (st.ffAD->type.in(ID($dffe), ID($sdffe))) {
+ bool pol = st.ffAD->getParam(ID::EN_POLARITY).as_bool();
+ SigSpec S = st.ffAD->getPort(ID::EN);
+ cell->setPort(ID(CEAD), pol ? S : pm.module->Not(NEW_ID, S));
}
else
cell->setPort(ID(CEAD), State::S1);
@@ -363,30 +364,24 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm)
{
cell->setPort(ID::CLK, st.clock);
- auto f = [&pm,cell](SigSpec &A, Cell* ff, Cell* cemux, bool cepol, IdString ceport, Cell* rstmux, bool rstpol, IdString rstport) {
+ auto f = [&pm,cell](SigSpec &A, Cell* ff, IdString ceport, IdString rstport) {
SigSpec D = ff->getPort(ID::D);
SigSpec Q = pm.sigmap(ff->getPort(ID::Q));
if (!A.empty())
A.replace(Q, D);
- if (rstmux) {
- SigSpec Y = rstmux->getPort(ID::Y);
- SigSpec AB = rstmux->getPort(rstpol ? ID::A : ID::B);
- if (!A.empty())
- A.replace(Y, AB);
- if (rstport != IdString()) {
- SigSpec S = rstmux->getPort(ID::S);
- cell->setPort(rstport, rstpol ? S : pm.module->Not(NEW_ID, S));
+ if (rstport != IdString()) {
+ if (ff->type.in(ID($sdff), ID($sdffe))) {
+ SigSpec srst = ff->getPort(ID::SRST);
+ bool rstpol = ff->getParam(ID::SRST_POLARITY).as_bool();
+ cell->setPort(rstport, rstpol ? srst : pm.module->Not(NEW_ID, srst));
+ } else {
+ cell->setPort(rstport, State::S0);
}
}
- else if (rstport != IdString())
- cell->setPort(rstport, State::S0);
- if (cemux) {
- SigSpec Y = cemux->getPort(ID::Y);
- SigSpec BA = cemux->getPort(cepol ? ID::B : ID::A);
- SigSpec S = cemux->getPort(ID::S);
- if (!A.empty())
- A.replace(Y, BA);
- cell->setPort(ceport, cepol ? S : pm.module->Not(NEW_ID, S));
+ if (ff->type.in(ID($dffe), ID($sdffe))) {
+ SigSpec ce = ff->getPort(ID::EN);
+ bool cepol = ff->getParam(ID::EN_POLARITY).as_bool();
+ cell->setPort(ceport, cepol ? ce : pm.module->Not(NEW_ID, ce));
}
else
cell->setPort(ceport, State::S1);
@@ -404,9 +399,9 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm)
if (st.ffA2) {
SigSpec A = cell->getPort(ID::A);
- f(A, st.ffA2, st.ffA2cemux, st.ffA2cepol, ID(CEA2), st.ffA2rstmux, st.ffArstpol, ID(RSTA));
+ f(A, st.ffA2, ID(CEA2), ID(RSTA));
if (st.ffA1) {
- f(A, st.ffA1, st.ffA1cemux, st.ffA1cepol, ID(CEA1), st.ffA1rstmux, st.ffArstpol, IdString());
+ f(A, st.ffA1, ID(CEA1), IdString());
cell->setParam(ID(AREG), 2);
cell->setParam(ID(ACASCREG), 2);
}
@@ -419,9 +414,9 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm)
}
if (st.ffB2) {
SigSpec B = cell->getPort(ID::B);
- f(B, st.ffB2, st.ffB2cemux, st.ffB2cepol, ID(CEB2), st.ffB2rstmux, st.ffBrstpol, ID(RSTB));
+ f(B, st.ffB2, ID(CEB2), ID(RSTB));
if (st.ffB1) {
- f(B, st.ffB1, st.ffB1cemux, st.ffB1cepol, ID(CEB1), st.ffB1rstmux, st.ffBrstpol, IdString());
+ f(B, st.ffB1, ID(CEB1), IdString());
cell->setParam(ID(BREG), 2);
cell->setParam(ID(BCASCREG), 2);
}
@@ -434,20 +429,20 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm)
}
if (st.ffD) {
SigSpec D = cell->getPort(ID::D);
- f(D, st.ffD, st.ffDcemux, st.ffDcepol, ID(CED), st.ffDrstmux, st.ffDrstpol, ID(RSTD));
+ f(D, st.ffD, ID(CED), ID(RSTD));
pm.add_siguser(D, cell);
cell->setPort(ID::D, D);
cell->setParam(ID(DREG), 1);
}
if (st.ffM) {
SigSpec M; // unused
- f(M, st.ffM, st.ffMcemux, st.ffMcepol, ID(CEM), st.ffMrstmux, st.ffMrstpol, ID(RSTM));
+ f(M, st.ffM, ID(CEM), ID(RSTM));
st.ffM->connections_.at(ID::Q).replace(st.sigM, pm.module->addWire(NEW_ID, GetSize(st.sigM)));
cell->setParam(ID(MREG), State::S1);
}
if (st.ffP) {
SigSpec P; // unused
- f(P, st.ffP, st.ffPcemux, st.ffPcepol, ID(CEP), st.ffPrstmux, st.ffPrstpol, ID(RSTP));
+ f(P, st.ffP, ID(CEP), ID(RSTP));
st.ffP->connections_.at(ID::Q).replace(st.sigP, pm.module->addWire(NEW_ID, GetSize(st.sigP)));
cell->setParam(ID(PREG), State::S1);
}
@@ -495,16 +490,16 @@ void xilinx_dsp48a_pack(xilinx_dsp48a_pm &pm)
log("Analysing %s.%s for Xilinx DSP48A/DSP48A1 packing.\n", log_id(pm.module), log_id(st.dsp));
log_debug("preAdd: %s\n", log_id(st.preAdd, "--"));
- log_debug("ffA1: %s %s %s\n", log_id(st.ffA1, "--"), log_id(st.ffA1cemux, "--"), log_id(st.ffA1rstmux, "--"));
- log_debug("ffA0: %s %s %s\n", log_id(st.ffA0, "--"), log_id(st.ffA0cemux, "--"), log_id(st.ffA0rstmux, "--"));
- log_debug("ffB1: %s %s %s\n", log_id(st.ffB1, "--"), log_id(st.ffB1cemux, "--"), log_id(st.ffB1rstmux, "--"));
- log_debug("ffB0: %s %s %s\n", log_id(st.ffB0, "--"), log_id(st.ffB0cemux, "--"), log_id(st.ffB0rstmux, "--"));
- log_debug("ffD: %s %s %s\n", log_id(st.ffD, "--"), log_id(st.ffDcemux, "--"), log_id(st.ffDrstmux, "--"));
+ log_debug("ffA1: %s\n", log_id(st.ffA1, "--"));
+ log_debug("ffA0: %s\n", log_id(st.ffA0, "--"));
+ log_debug("ffB1: %s\n", log_id(st.ffB1, "--"));
+ log_debug("ffB0: %s\n", log_id(st.ffB0, "--"));
+ log_debug("ffD: %s\n", log_id(st.ffD, "--"));
log_debug("dsp: %s\n", log_id(st.dsp, "--"));
- log_debug("ffM: %s %s %s\n", log_id(st.ffM, "--"), log_id(st.ffMcemux, "--"), log_id(st.ffMrstmux, "--"));
+ log_debug("ffM: %s\n", log_id(st.ffM, "--"));
log_debug("postAdd: %s\n", log_id(st.postAdd, "--"));
log_debug("postAddMux: %s\n", log_id(st.postAddMux, "--"));
- log_debug("ffP: %s %s %s\n", log_id(st.ffP, "--"), log_id(st.ffPcemux, "--"), log_id(st.ffPrstmux, "--"));
+ log_debug("ffP: %s\n", log_id(st.ffP, "--"));
Cell *cell = st.dsp;
SigSpec &opmode = cell->connections_.at(ID(OPMODE));
@@ -556,30 +551,24 @@ void xilinx_dsp48a_pack(xilinx_dsp48a_pm &pm)
{
cell->setPort(ID::CLK, st.clock);
- auto f = [&pm,cell](SigSpec &A, Cell* ff, Cell* cemux, bool cepol, IdString ceport, Cell* rstmux, bool rstpol, IdString rstport) {
+ auto f = [&pm,cell](SigSpec &A, Cell* ff, IdString ceport, IdString rstport) {
SigSpec D = ff->getPort(ID::D);
SigSpec Q = pm.sigmap(ff->getPort(ID::Q));
if (!A.empty())
A.replace(Q, D);
- if (rstmux) {
- SigSpec Y = rstmux->getPort(ID::Y);
- SigSpec AB = rstmux->getPort(rstpol ? ID::A : ID::B);
- if (!A.empty())
- A.replace(Y, AB);
- if (rstport != IdString()) {
- SigSpec S = rstmux->getPort(ID::S);
- cell->setPort(rstport, rstpol ? S : pm.module->Not(NEW_ID, S));
+ if (rstport != IdString()) {
+ if (ff->type.in(ID($sdff), ID($sdffe))) {
+ SigSpec srst = ff->getPort(ID::SRST);
+ bool rstpol = ff->getParam(ID::SRST_POLARITY).as_bool();
+ cell->setPort(rstport, rstpol ? srst : pm.module->Not(NEW_ID, srst));
+ } else {
+ cell->setPort(rstport, State::S0);
}
}
- else if (rstport != IdString())
- cell->setPort(rstport, State::S0);
- if (cemux) {
- SigSpec Y = cemux->getPort(ID::Y);
- SigSpec BA = cemux->getPort(cepol ? ID::B : ID::A);
- SigSpec S = cemux->getPort(ID::S);
- if (!A.empty())
- A.replace(Y, BA);
- cell->setPort(ceport, cepol ? S : pm.module->Not(NEW_ID, S));
+ if (ff->type.in(ID($dffe), ID($sdffe))) {
+ SigSpec ce = ff->getPort(ID::EN);
+ bool cepol = ff->getParam(ID::EN_POLARITY).as_bool();
+ cell->setPort(ceport, cepol ? ce : pm.module->Not(NEW_ID, ce));
}
else
cell->setPort(ceport, State::S1);
@@ -598,11 +587,11 @@ void xilinx_dsp48a_pack(xilinx_dsp48a_pm &pm)
if (st.ffA0 || st.ffA1) {
SigSpec A = cell->getPort(ID::A);
if (st.ffA1) {
- f(A, st.ffA1, st.ffA1cemux, st.ffAcepol, ID(CEA), st.ffA1rstmux, st.ffArstpol, ID(RSTA));
+ f(A, st.ffA1, ID(CEA), ID(RSTA));
cell->setParam(ID(A1REG), 1);
}
if (st.ffA0) {
- f(A, st.ffA0, st.ffA0cemux, st.ffAcepol, ID(CEA), st.ffA0rstmux, st.ffArstpol, ID(RSTA));
+ f(A, st.ffA0, ID(CEA), ID(RSTA));
cell->setParam(ID(A0REG), 1);
}
pm.add_siguser(A, cell);
@@ -611,11 +600,11 @@ void xilinx_dsp48a_pack(xilinx_dsp48a_pm &pm)
if (st.ffB0 || st.ffB1) {
SigSpec B = cell->getPort(ID::B);
if (st.ffB1) {
- f(B, st.ffB1, st.ffB1cemux, st.ffBcepol, ID(CEB), st.ffB1rstmux, st.ffBrstpol, ID(RSTB));
+ f(B, st.ffB1, ID(CEB), ID(RSTB));
cell->setParam(ID(B1REG), 1);
}
if (st.ffB0) {
- f(B, st.ffB0, st.ffB0cemux, st.ffBcepol, ID(CEB), st.ffB0rstmux, st.ffBrstpol, ID(RSTB));
+ f(B, st.ffB0, ID(CEB), ID(RSTB));
cell->setParam(ID(B0REG), 1);
}
pm.add_siguser(B, cell);
@@ -623,20 +612,20 @@ void xilinx_dsp48a_pack(xilinx_dsp48a_pm &pm)
}
if (st.ffD) {
SigSpec D = cell->getPort(ID::D);
- f(D, st.ffD, st.ffDcemux, st.ffDcepol, ID(CED), st.ffDrstmux, st.ffDrstpol, ID(RSTD));
+ f(D, st.ffD, ID(CED), ID(RSTD));
pm.add_siguser(D, cell);
cell->setPort(ID::D, D);
cell->setParam(ID(DREG), 1);
}
if (st.ffM) {
SigSpec M; // unused
- f(M, st.ffM, st.ffMcemux, st.ffMcepol, ID(CEM), st.ffMrstmux, st.ffMrstpol, ID(RSTM));
+ f(M, st.ffM, ID(CEM), ID(RSTM));
st.ffM->connections_.at(ID::Q).replace(st.sigM, pm.module->addWire(NEW_ID, GetSize(st.sigM)));
cell->setParam(ID(MREG), State::S1);
}
if (st.ffP) {
SigSpec P; // unused
- f(P, st.ffP, st.ffPcemux, st.ffPcepol, ID(CEP), st.ffPrstmux, st.ffPrstpol, ID(RSTP));
+ f(P, st.ffP, ID(CEP), ID(RSTP));
st.ffP->connections_.at(ID::Q).replace(st.sigP, pm.module->addWire(NEW_ID, GetSize(st.sigP)));
cell->setParam(ID(PREG), State::S1);
}
@@ -677,7 +666,7 @@ void xilinx_dsp_packC(xilinx_dsp_CREG_pm &pm)
auto &st = pm.st_xilinx_dsp_packC;
log_debug("Analysing %s.%s for Xilinx DSP packing (CREG).\n", log_id(pm.module), log_id(st.dsp));
- log_debug("ffC: %s %s %s\n", log_id(st.ffC, "--"), log_id(st.ffCcemux, "--"), log_id(st.ffCrstmux, "--"));
+ log_debug("ffC: %s\n", log_id(st.ffC, "--"));
Cell *cell = st.dsp;
@@ -685,30 +674,24 @@ void xilinx_dsp_packC(xilinx_dsp_CREG_pm &pm)
{
cell->setPort(ID::CLK, st.clock);
- auto f = [&pm,cell](SigSpec &A, Cell* ff, Cell* cemux, bool cepol, IdString ceport, Cell* rstmux, bool rstpol, IdString rstport) {
+ auto f = [&pm,cell](SigSpec &A, Cell* ff, IdString ceport, IdString rstport) {
SigSpec D = ff->getPort(ID::D);
SigSpec Q = pm.sigmap(ff->getPort(ID::Q));
if (!A.empty())
A.replace(Q, D);
- if (rstmux) {
- SigSpec Y = rstmux->getPort(ID::Y);
- SigSpec AB = rstmux->getPort(rstpol ? ID::A : ID::B);
- if (!A.empty())
- A.replace(Y, AB);
- if (rstport != IdString()) {
- SigSpec S = rstmux->getPort(ID::S);
- cell->setPort(rstport, rstpol ? S : pm.module->Not(NEW_ID, S));
+ if (rstport != IdString()) {
+ if (ff->type.in(ID($sdff), ID($sdffe))) {
+ SigSpec srst = ff->getPort(ID::SRST);
+ bool rstpol = ff->getParam(ID::SRST_POLARITY).as_bool();
+ cell->setPort(rstport, rstpol ? srst : pm.module->Not(NEW_ID, srst));
+ } else {
+ cell->setPort(rstport, State::S0);
}
}
- else if (rstport != IdString())
- cell->setPort(rstport, State::S0);
- if (cemux) {
- SigSpec Y = cemux->getPort(ID::Y);
- SigSpec BA = cemux->getPort(cepol ? ID::B : ID::A);
- SigSpec S = cemux->getPort(ID::S);
- if (!A.empty())
- A.replace(Y, BA);
- cell->setPort(ceport, cepol ? S : pm.module->Not(NEW_ID, S));
+ if (ff->type.in(ID($dffe), ID($sdffe))) {
+ SigSpec ce = ff->getPort(ID::EN);
+ bool cepol = ff->getParam(ID::EN_POLARITY).as_bool();
+ cell->setPort(ceport, cepol ? ce : pm.module->Not(NEW_ID, ce));
}
else
cell->setPort(ceport, State::S1);
@@ -726,7 +709,7 @@ void xilinx_dsp_packC(xilinx_dsp_CREG_pm &pm)
if (st.ffC) {
SigSpec C = cell->getPort(ID::C);
- f(C, st.ffC, st.ffCcemux, st.ffCcepol, ID(CEC), st.ffCrstmux, st.ffCrstpol, ID(RSTC));
+ f(C, st.ffC, ID(CEC), ID(RSTC));
pm.add_siguser(C, cell);
cell->setPort(ID::C, C);
cell->setParam(ID(CREG), 1);
@@ -744,7 +727,7 @@ void xilinx_dsp_packC(xilinx_dsp_CREG_pm &pm)
struct XilinxDspPass : public Pass {
XilinxDspPass() : Pass("xilinx_dsp", "Xilinx: pack resources into DSPs") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -785,7 +768,7 @@ struct XilinxDspPass : public Pass {
log(" default: xc7\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing XILINX_DSP pass (pack resources into DSPs).\n");
diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg
index d40f073c9..0cd23c09d 100644
--- a/passes/pmgen/xilinx_dsp.pmg
+++ b/passes/pmgen/xilinx_dsp.pmg
@@ -2,9 +2,7 @@
// forms the `xilinx_dsp` pass described in xilinx_dsp.cc
// At a high level, it works as follows:
// ( 1) Starting from a DSP48E1 cell
-// ( 2) Match the driver of the 'A' input to a possible $dff cell (ADREG)
-// (attached to at most two $mux cells that implement clock-enable or
-// reset functionality, using a subpattern discussed below)
+// ( 2) Match the driver of the 'A' input to a possible $sdffe cell (ADREG)
// If ADREG matched, treat 'A' input as input of ADREG
// ( 3) Match the driver of the 'A' and 'D' inputs for a possible $add cell
// (pre-adder)
@@ -44,7 +42,7 @@
// DSP48E1 cells inferred from multiply operations by Yosys, as well as for
// user instantiations that may already contain the cells being packed...
// (though the latter is currently untested)
-// - Since the $dff-with-optional-clock-enable-or-reset-mux pattern is used
+// - Since the $sdffe pattern is used
// for each *REG match, it has been factored out into two subpatterns:
// in_dffe and out_dffe located at the bottom of this file.
// - Matching for pattern detector features is currently incomplete. For
@@ -57,20 +55,15 @@ pattern xilinx_dsp_pack
state <SigBit> clock
state <SigSpec> sigA sigB sigC sigD sigM sigP
state <IdString> postAddAB postAddMuxAB
-state <bool> ffA1cepol ffA2cepol ffADcepol ffB1cepol ffB2cepol ffDcepol ffMcepol ffPcepol
-state <bool> ffArstpol ffADrstpol ffBrstpol ffDrstpol ffMrstpol ffPrstpol
-state <Cell*> ffAD ffADcemux ffADrstmux ffA1 ffA1cemux ffA1rstmux ffA2 ffA2cemux ffA2rstmux
-state <Cell*> ffB1 ffB1cemux ffB1rstmux ffB2 ffB2cemux ffB2rstmux
-state <Cell*> ffD ffDcemux ffDrstmux ffM ffMcemux ffMrstmux ffP ffPcemux ffPrstmux
+state <Cell*> ffAD ffA1 ffA2
+state <Cell*> ffB1 ffB2
+state <Cell*> ffD ffM ffP
// Variables used for subpatterns
state <SigSpec> argQ argD
-state <bool> ffcepol ffrstpol
-state <int> ffoffset
udata <SigSpec> dffD dffQ
udata <SigBit> dffclock
-udata <Cell*> dff dffcemux dffrstmux
-udata <bool> dffcepol dffrstpol
+udata <Cell*> dff
// (1) Starting from a DSP48E1 cell
match dsp
@@ -115,25 +108,15 @@ code sigA sigB sigC sigD sigM clock
clock = port(dsp, \CLK, SigBit());
endcode
-// (2) Match the driver of the 'A' input to a possible $dff cell (ADREG)
-// (attached to at most two $mux cells that implement clock-enable or
-// reset functionality, using a subpattern discussed above)
+// (2) Match the driver of the 'A' input to a possible $sdffe cell (ADREG)
// If matched, treat 'A' input as input of ADREG
-code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock
+code argQ ffAD sigA clock
if (param(dsp, \ADREG).as_int() == 0) {
argQ = sigA;
subpattern(in_dffe);
if (dff) {
ffAD = dff;
clock = dffclock;
- if (dffrstmux) {
- ffADrstmux = dffrstmux;
- ffADrstpol = dffrstpol;
- }
- if (dffcemux) {
- ffADcemux = dffcemux;
- ffADcepol = dffcepol;
- }
sigA = dffD;
}
}
@@ -172,7 +155,7 @@ endcode
// (4) If pre-adder was present, find match 'A' input for A2REG
// If pre-adder was not present, move ADREG to A2REG
// Then match 'A' input for A1REG
-code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock ffA2 ffA2cemux ffA2rstmux ffA2cepol ffArstpol ffA1 ffA1cemux ffA1rstmux ffA1cepol
+code argQ ffAD sigA clock ffA2 ffA1
// Only search for ffA2 if there was a pre-adder
// (otherwise ffA2 would have been matched as ffAD)
if (preAdd) {
@@ -182,14 +165,6 @@ code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock ffA2 ffA2cem
if (dff) {
ffA2 = dff;
clock = dffclock;
- if (dffrstmux) {
- ffA2rstmux = dffrstmux;
- ffArstpol = dffrstpol;
- }
- if (dffcemux) {
- ffA2cepol = dffcepol;
- ffA2cemux = dffcemux;
- }
sigA = dffD;
}
}
@@ -197,12 +172,8 @@ code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock ffA2 ffA2cem
// And if there wasn't a pre-adder,
// move AD register to A
else if (ffAD) {
- log_assert(!ffA2 && !ffA2cemux && !ffA2rstmux);
+ log_assert(!ffA2);
std::swap(ffA2, ffAD);
- std::swap(ffA2cemux, ffADcemux);
- std::swap(ffA2rstmux, ffADrstmux);
- ffA2cepol = ffADcepol;
- ffArstpol = ffADrstpol;
}
// Now attempt to match A1
@@ -210,23 +181,23 @@ code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock ffA2 ffA2cem
argQ = sigA;
subpattern(in_dffe);
if (dff) {
- if ((ffA2rstmux != nullptr) ^ (dffrstmux != nullptr))
+ if (dff->type != ffA2->type)
goto ffA1_end;
- if (dffrstmux) {
- if (ffArstpol != dffrstpol)
+ if (dff->type.in($sdff, $sdffe, $sdffce)) {
+ if (param(dff, \SRST_POLARITY) != param(ffA2, \SRST_POLARITY))
goto ffA1_end;
- if (port(ffA2rstmux, \S) != port(dffrstmux, \S))
+ if (port(dff, \SRST) != port(ffA2, \SRST))
+ goto ffA1_end;
+ }
+ if (dff->type.in($dffe, $sdffe, $sdffce)) {
+ if (param(dff, \EN_POLARITY) != param(ffA2, \EN_POLARITY))
+ goto ffA1_end;
+ if (port(dff, \EN) != port(ffA2, \EN))
goto ffA1_end;
- ffA1rstmux = dffrstmux;
}
ffA1 = dff;
clock = dffclock;
-
- if (dffcemux) {
- ffA1cemux = dffcemux;
- ffA1cepol = dffcepol;
- }
sigA = dffD;
ffA1_end: ;
@@ -236,21 +207,13 @@ endcode
// (5) Match 'B' input for B2REG
// If B2REG, then match 'B' input for B1REG
-code argQ ffB2 ffB2cemux ffB2rstmux ffB2cepol ffBrstpol sigB clock ffB1 ffB1cemux ffB1rstmux ffB1cepol
+code argQ ffB2 sigB clock ffB1
if (param(dsp, \BREG).as_int() == 0) {
argQ = sigB;
subpattern(in_dffe);
if (dff) {
ffB2 = dff;
clock = dffclock;
- if (dffrstmux) {
- ffB2rstmux = dffrstmux;
- ffBrstpol = dffrstpol;
- }
- if (dffcemux) {
- ffB2cemux = dffcemux;
- ffB2cepol = dffcepol;
- }
sigB = dffD;
// Now attempt to match B1
@@ -258,23 +221,23 @@ code argQ ffB2 ffB2cemux ffB2rstmux ffB2cepol ffBrstpol sigB clock ffB1 ffB1cemu
argQ = sigB;
subpattern(in_dffe);
if (dff) {
- if ((ffB2rstmux != nullptr) ^ (dffrstmux != nullptr))
+ if (dff->type != ffB2->type)
goto ffB1_end;
- if (dffrstmux) {
- if (ffBrstpol != dffrstpol)
+ if (dff->type.in($sdff, $sdffe, $sdffce)) {
+ if (param(dff, \SRST_POLARITY) != param(ffB2, \SRST_POLARITY))
+ goto ffB1_end;
+ if (port(dff, \SRST) != port(ffB2, \SRST))
+ goto ffB1_end;
+ }
+ if (dff->type.in($dffe, $sdffe, $sdffce)) {
+ if (param(dff, \EN_POLARITY) != param(ffB2, \EN_POLARITY))
goto ffB1_end;
- if (port(ffB2rstmux, \S) != port(dffrstmux, \S))
+ if (port(dff, \EN) != port(ffB2, \EN))
goto ffB1_end;
- ffB1rstmux = dffrstmux;
}
ffB1 = dff;
clock = dffclock;
-
- if (dffcemux) {
- ffB1cemux = dffcemux;
- ffB1cepol = dffcepol;
- }
sigB = dffD;
ffB1_end: ;
@@ -286,42 +249,26 @@ ffB1_end: ;
endcode
// (6) Match 'D' input for DREG
-code argQ ffD ffDcemux ffDrstmux ffDcepol ffDrstpol sigD clock
+code argQ ffD sigD clock
if (param(dsp, \DREG).as_int() == 0) {
argQ = sigD;
subpattern(in_dffe);
if (dff) {
ffD = dff;
clock = dffclock;
- if (dffrstmux) {
- ffDrstmux = dffrstmux;
- ffDrstpol = dffrstpol;
- }
- if (dffcemux) {
- ffDcemux = dffcemux;
- ffDcepol = dffcepol;
- }
sigD = dffD;
}
}
endcode
// (7) Match 'P' output that exclusively drives an MREG
-code argD ffM ffMcemux ffMrstmux ffMcepol ffMrstpol sigM sigP clock
+code argD ffM sigM sigP clock
if (param(dsp, \MREG).as_int() == 0 && nusers(sigM) == 2) {
argD = sigM;
subpattern(out_dffe);
if (dff) {
ffM = dff;
clock = dffclock;
- if (dffrstmux) {
- ffMrstmux = dffrstmux;
- ffMrstpol = dffrstpol;
- }
- if (dffcemux) {
- ffMcemux = dffcemux;
- ffMcepol = dffcepol;
- }
sigM = dffQ;
}
}
@@ -340,9 +287,7 @@ match postAdd
select postAdd->type.in($add)
select GetSize(port(postAdd, \Y)) <= 48
choice <IdString> AB {\A, \B}
- select nusers(port(postAdd, AB)) <= 3
- filter ffMcemux || nusers(port(postAdd, AB)) == 2
- filter !ffMcemux || nusers(port(postAdd, AB)) == 3
+ select nusers(port(postAdd, AB)) == 2
index <SigBit> port(postAdd, AB)[0] === sigP[0]
filter GetSize(port(postAdd, AB)) >= GetSize(sigP)
@@ -362,25 +307,14 @@ code sigC sigP
endcode
// (9) Match 'P' output that exclusively drives a PREG
-code argD ffP ffPcemux ffPrstmux ffPcepol ffPrstpol sigP clock
+code argD ffP sigP clock
if (param(dsp, \PREG).as_int() == 0) {
- int users = 2;
- // If ffMcemux and no postAdd new-value net must have three users: ffMcemux, ffM and ffPcemux
- if (ffMcemux && !postAdd) users++;
- if (nusers(sigP) == users) {
+ if (nusers(sigP) == 2) {
argD = sigP;
subpattern(out_dffe);
if (dff) {
ffP = dff;
clock = dffclock;
- if (dffrstmux) {
- ffPrstmux = dffrstmux;
- ffPrstpol = dffrstpol;
- }
- if (dffcemux) {
- ffPcemux = dffcemux;
- ffPcepol = dffcepol;
- }
sigP = dffQ;
}
}
@@ -441,22 +375,9 @@ endcode
// #######################
// Subpattern for matching against input registers, based on knowledge of the
-// 'Q' input. Typically, identifying registers with clock-enable and reset
-// capability would be a task would be handled by other Yosys passes such as
-// dff2dffe, but since DSP inference happens much before this, these patterns
-// have to be manually identified.
-// At a high level:
-// (1) Starting from a $dff cell that (partially or fully) drives the given
-// 'Q' argument
-// (2) Match for a $mux cell implementing synchronous reset semantics ---
-// one that exclusively drives the 'D' input of the $dff, with one of its
-// $mux inputs being fully zero
-// (3) Match for a $mux cell implement clock enable semantics --- one that
-// exclusively drives the 'D' input of the $dff (or the other input of
-// the reset $mux) and where one of this $mux's inputs is connected to
-// the 'Q' output of the $dff
+// 'Q' input.
subpattern in_dffe
-arg argD argQ clock
+arg argQ clock
code
dff = nullptr;
@@ -479,13 +400,14 @@ code
}
endcode
-// (1) Starting from a $dff cell that (partially or fully) drives the given
-// 'Q' argument
match ff
- select ff->type.in($dff)
+ select ff->type.in($dff, $dffe, $sdff, $sdffe)
// DSP48E1 does not support clock inversion
select param(ff, \CLK_POLARITY).as_bool()
+ // Check that reset value, if present, is fully 0.
+ filter ff->type.in($dff, $dffe) || param(ff, \SRST_VALUE).is_fully_zero()
+
slice offset GetSize(port(ff, \D))
index <SigBit> port(ff, \Q)[offset] === argQ[0]
@@ -494,82 +416,16 @@ match ff
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
filter clock == SigBit() || port(ff, \CLK) == clock
-
- set ffoffset offset
endmatch
-code argQ argD
+code argQ
SigSpec Q = port(ff, \Q);
dff = ff;
dffclock = port(ff, \CLK);
dffD = argQ;
- argD = port(ff, \D);
+ SigSpec D = port(ff, \D);
argQ = Q;
- dffD.replace(argQ, argD);
- // Only search for ffrstmux if dffD only
- // has two (ff, ffrstmux) users
- if (nusers(dffD) > 2)
- argD = SigSpec();
-endcode
-
-// (2) Match for a $mux cell implementing synchronous reset semantics ---
-// exclusively drives the 'D' input of the $dff, with one of the $mux
-// inputs being fully zero
-match ffrstmux
- if !argD.empty()
- select ffrstmux->type.in($mux)
- index <SigSpec> port(ffrstmux, \Y) === argD
-
- choice <IdString> BA {\B, \A}
- // DSP48E1 only supports reset to zero
- select port(ffrstmux, BA).is_fully_zero()
-
- define <bool> pol (BA == \B)
- set ffrstpol pol
- semioptional
-endmatch
-
-code argD
- if (ffrstmux) {
- dffrstmux = ffrstmux;
- dffrstpol = ffrstpol;
- argD = port(ffrstmux, ffrstpol ? \A : \B);
- dffD.replace(port(ffrstmux, \Y), argD);
-
- // Only search for ffcemux if argQ has at
- // least 3 users (ff, <upstream>, ffrstmux) and
- // dffD only has two (ff, ffrstmux)
- if (!(nusers(argQ) >= 3 && nusers(dffD) == 2))
- argD = SigSpec();
- }
- else
- dffrstmux = nullptr;
-endcode
-
-// (3) Match for a $mux cell implement clock enable semantics --- one that
-// exclusively drives the 'D' input of the $dff (or the other input of
-// the reset $mux) and where one of this $mux's inputs is connected to
-// the 'Q' output of the $dff
-match ffcemux
- if !argD.empty()
- select ffcemux->type.in($mux)
- index <SigSpec> port(ffcemux, \Y) === argD
- choice <IdString> AB {\A, \B}
- index <SigSpec> port(ffcemux, AB) === argQ
- define <bool> pol (AB == \A)
- set ffcepol pol
- semioptional
-endmatch
-
-code argD
- if (ffcemux) {
- dffcemux = ffcemux;
- dffcepol = ffcepol;
- argD = port(ffcemux, ffcepol ? \B : \A);
- dffD.replace(port(ffcemux, \Y), argD);
- }
- else
- dffcemux = nullptr;
+ dffD.replace(argQ, D);
endcode
// #######################
@@ -597,119 +453,26 @@ code
reject;
endcode
-// (1) Starting from an optional $mux cell that implements clock enable
-// semantics --- one where the given 'D' argument (partially or fully)
-// drives one of its two inputs
-match ffcemux
- select ffcemux->type.in($mux)
- // ffcemux output must have two users: ffcemux and ff.D
- select nusers(port(ffcemux, \Y)) == 2
-
- choice <IdString> AB {\A, \B}
- // keep-last-value net must have at least three users: ffcemux, ff, downstream sink(s)
- select nusers(port(ffcemux, AB)) >= 3
-
- slice offset GetSize(port(ffcemux, \Y))
- define <IdString> BA (AB == \A ? \B : \A)
- index <SigBit> port(ffcemux, BA)[offset] === argD[0]
-
- // Check that the rest of argD is present
- filter GetSize(port(ffcemux, BA)) >= offset + GetSize(argD)
- filter port(ffcemux, BA).extract(offset, GetSize(argD)) == argD
-
- set ffoffset offset
- define <bool> pol (AB == \A)
- set ffcepol pol
-
- semioptional
-endmatch
-
-code argD argQ
- dffcemux = ffcemux;
- if (ffcemux) {
- SigSpec BA = port(ffcemux, ffcepol ? \B : \A);
- SigSpec Y = port(ffcemux, \Y);
- argQ = argD;
- argD.replace(BA, Y);
- argQ.replace(BA, port(ffcemux, ffcepol ? \A : \B));
-
- dffcemux = ffcemux;
- dffcepol = ffcepol;
- }
-endcode
-
-// (2) Starting from, or continuing onto, another optional $mux cell that
-// implements synchronous reset semantics --- one where the given 'D'
-// argument (or the clock enable $mux output) drives one of its two inputs
-// and where the other input is fully zero
-match ffrstmux
- select ffrstmux->type.in($mux)
- // ffrstmux output must have two users: ffrstmux and ff.D
- select nusers(port(ffrstmux, \Y)) == 2
-
- choice <IdString> BA {\B, \A}
- // DSP48E1 only supports reset to zero
- select port(ffrstmux, BA).is_fully_zero()
-
- slice offset GetSize(port(ffrstmux, \Y))
- define <IdString> AB (BA == \B ? \A : \B)
- index <SigBit> port(ffrstmux, AB)[offset] === argD[0]
-
- // Check that offset is consistent
- filter !ffcemux || ffoffset == offset
- // Check that the rest of argD is present
- filter GetSize(port(ffrstmux, AB)) >= offset + GetSize(argD)
- filter port(ffrstmux, AB).extract(offset, GetSize(argD)) == argD
-
- set ffoffset offset
- define <bool> pol (AB == \A)
- set ffrstpol pol
-
- semioptional
-endmatch
-
-code argD argQ
- dffrstmux = ffrstmux;
- if (ffrstmux) {
- SigSpec AB = port(ffrstmux, ffrstpol ? \A : \B);
- SigSpec Y = port(ffrstmux, \Y);
- argD.replace(AB, Y);
-
- dffrstmux = ffrstmux;
- dffrstpol = ffrstpol;
- }
-endcode
-
-// (3) Match for a $dff cell (whose 'D' input is the 'D' argument, or the
-// output of the previous clock enable or reset $mux cells)
match ff
- select ff->type.in($dff)
+ select ff->type.in($dff, $dffe, $sdff, $sdffe)
// DSP48E1 does not support clock inversion
select param(ff, \CLK_POLARITY).as_bool()
slice offset GetSize(port(ff, \D))
index <SigBit> port(ff, \D)[offset] === argD[0]
- // Check that offset is consistent
- filter (!ffcemux && !ffrstmux) || ffoffset == offset
// Check that the rest of argD is present
filter GetSize(port(ff, \D)) >= offset + GetSize(argD)
filter port(ff, \D).extract(offset, GetSize(argD)) == argD
- // Check that FF.Q is connected to CE-mux
- filter !ffcemux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
filter clock == SigBit() || port(ff, \CLK) == clock
-
- set ffoffset offset
endmatch
code argQ
SigSpec D = port(ff, \D);
SigSpec Q = port(ff, \Q);
- if (!ffcemux) {
- argQ = argD;
- argQ.replace(D, Q);
- }
+ argQ = argD;
+ argQ.replace(D, Q);
// Abandon matches when 'Q' has a non-zero init attribute set
// (not supported by DSP48E1)
diff --git a/passes/pmgen/xilinx_dsp48a.pmg b/passes/pmgen/xilinx_dsp48a.pmg
index 16f5e598d..dce1b61b0 100644
--- a/passes/pmgen/xilinx_dsp48a.pmg
+++ b/passes/pmgen/xilinx_dsp48a.pmg
@@ -4,8 +4,6 @@
// At a high level, it works as follows:
// ( 1) Starting from a DSP48A/DSP48A1 cell
// ( 2) Match the driver of the 'B' input to a possible $dff cell (B1REG)
-// (attached to at most two $mux cells that implement clock-enable or
-// reset functionality, using a subpattern discussed below)
// If B1REG matched, treat 'B' input as input of B1REG
// ( 3) Match the driver of the 'B' and 'D' inputs for a possible $add cell
// (pre-adder)
@@ -40,20 +38,15 @@ pattern xilinx_dsp48a_pack
state <SigBit> clock
state <SigSpec> sigA sigB sigC sigD sigM sigP
state <IdString> postAddAB postAddMuxAB
-state <bool> ffAcepol ffBcepol ffDcepol ffMcepol ffPcepol
-state <bool> ffArstpol ffBrstpol ffDrstpol ffMrstpol ffPrstpol
-state <Cell*> ffA0 ffA0cemux ffA0rstmux ffA1 ffA1cemux ffA1rstmux
-state <Cell*> ffB0 ffB0cemux ffB0rstmux ffB1 ffB1cemux ffB1rstmux
-state <Cell*> ffD ffDcemux ffDrstmux ffM ffMcemux ffMrstmux ffP ffPcemux ffPrstmux
+state <Cell*> ffA0 ffA1
+state <Cell*> ffB0 ffB1
+state <Cell*> ffD ffM ffP
// Variables used for subpatterns
state <SigSpec> argQ argD
-state <bool> ffcepol ffrstpol
-state <int> ffoffset
udata <SigSpec> dffD dffQ
udata <SigBit> dffclock
-udata <Cell*> dff dffcemux dffrstmux
-udata <bool> dffcepol dffrstpol
+udata <Cell*> dff
// (1) Starting from a DSP48A/DSP48A1 cell
match dsp
@@ -98,21 +91,13 @@ endcode
// (attached to at most two $mux cells that implement clock-enable or
// reset functionality, using a subpattern discussed above)
// If matched, treat 'B' input as input of B1REG
-code argQ ffB1 ffB1cemux ffB1rstmux ffBcepol ffBrstpol sigB clock
+code argQ ffB1 sigB clock
if (param(dsp, \B1REG).as_int() == 0 && param(dsp, \B0REG).as_int() == 0 && port(dsp, \OPMODE, SigSpec()).extract(4, 1).is_fully_zero()) {
argQ = sigB;
subpattern(in_dffe);
if (dff) {
ffB1 = dff;
clock = dffclock;
- if (dffrstmux) {
- ffB1rstmux = dffrstmux;
- ffBrstpol = dffrstpol;
- }
- if (dffcemux) {
- ffB1cemux = dffcemux;
- ffBcepol = dffcepol;
- }
sigB = dffD;
}
}
@@ -147,41 +132,29 @@ code sigB sigD
endcode
// (4) Match 'B' input for B0REG
-code argQ ffB0 ffB0cemux ffB0rstmux ffBcepol ffBrstpol sigB clock
+code argQ ffB0 sigB clock
if (param(dsp, \B0REG).as_int() == 0) {
argQ = sigB;
subpattern(in_dffe);
if (dff) {
if (ffB1) {
- if ((ffB1rstmux != nullptr) ^ (dffrstmux != nullptr))
+ if (dff->type != ffB1->type)
goto ffB0_end;
- if ((ffB1cemux != nullptr) ^ (dffcemux != nullptr))
- goto ffB0_end;
- if (dffrstmux) {
- if (ffBrstpol != dffrstpol)
+ if (dff->type.in($sdff, $sdffe, $sdffce)) {
+ if (param(dff, \SRST_POLARITY) != param(ffB1, \SRST_POLARITY))
goto ffB0_end;
- if (port(ffB1rstmux, \S) != port(dffrstmux, \S))
+ if (port(dff, \SRST) != port(ffB1, \SRST))
goto ffB0_end;
- ffB0rstmux = dffrstmux;
}
- if (dffcemux) {
- if (ffBcepol != dffcepol)
+ if (dff->type.in($dffe, $sdffe, $sdffce)) {
+ if (param(dff, \EN_POLARITY) != param(ffB1, \EN_POLARITY))
goto ffB0_end;
- if (port(ffB1cemux, \S) != port(dffcemux, \S))
+ if (port(dff, \EN) != port(ffB1, \EN))
goto ffB0_end;
- ffB0cemux = dffcemux;
}
}
ffB0 = dff;
clock = dffclock;
- if (dffrstmux) {
- ffB0rstmux = dffrstmux;
- ffBrstpol = dffrstpol;
- }
- if (dffcemux) {
- ffB0cemux = dffcemux;
- ffBcepol = dffcepol;
- }
sigB = dffD;
}
}
@@ -190,21 +163,13 @@ endcode
// (5) Match 'A' input for A1REG
// If A1REG, then match 'A' input for A0REG
-code argQ ffA1 ffA1cemux ffA1rstmux ffAcepol ffArstpol sigA clock ffA0 ffA0cemux ffA0rstmux
+code argQ ffA1 sigA clock ffA0
if (param(dsp, \A0REG).as_int() == 0 && param(dsp, \A1REG).as_int() == 0) {
argQ = sigA;
subpattern(in_dffe);
if (dff) {
ffA1 = dff;
clock = dffclock;
- if (dffrstmux) {
- ffA1rstmux = dffrstmux;
- ffArstpol = dffrstpol;
- }
- if (dffcemux) {
- ffA1cemux = dffcemux;
- ffAcepol = dffcepol;
- }
sigA = dffD;
// Now attempt to match A0
@@ -212,32 +177,23 @@ code argQ ffA1 ffA1cemux ffA1rstmux ffAcepol ffArstpol sigA clock ffA0 ffA0cemux
argQ = sigA;
subpattern(in_dffe);
if (dff) {
- if ((ffA1rstmux != nullptr) ^ (dffrstmux != nullptr))
+ if (dff->type != ffA1->type)
goto ffA0_end;
- if ((ffA1cemux != nullptr) ^ (dffcemux != nullptr))
- goto ffA0_end;
- if (dffrstmux) {
- if (ffArstpol != dffrstpol)
+ if (dff->type.in($sdff, $sdffe, $sdffce)) {
+ if (param(dff, \SRST_POLARITY) != param(ffA1, \SRST_POLARITY))
goto ffA0_end;
- if (port(ffA1rstmux, \S) != port(dffrstmux, \S))
+ if (port(dff, \SRST) != port(ffA1, \SRST))
goto ffA0_end;
- ffA0rstmux = dffrstmux;
}
- if (dffcemux) {
- if (ffAcepol != dffcepol)
+ if (dff->type.in($dffe, $sdffe, $sdffce)) {
+ if (param(dff, \EN_POLARITY) != param(ffA1, \EN_POLARITY))
goto ffA0_end;
- if (port(ffA1cemux, \S) != port(dffcemux, \S))
+ if (port(dff, \EN) != port(ffA1, \EN))
goto ffA0_end;
- ffA0cemux = dffcemux;
}
ffA0 = dff;
clock = dffclock;
-
- if (dffcemux) {
- ffA0cemux = dffcemux;
- ffAcepol = dffcepol;
- }
sigA = dffD;
ffA0_end: ;
@@ -249,42 +205,26 @@ ffA0_end: ;
endcode
// (6) Match 'D' input for DREG
-code argQ ffD ffDcemux ffDrstmux ffDcepol ffDrstpol sigD clock
+code argQ ffD sigD clock
if (param(dsp, \DREG).as_int() == 0) {
argQ = sigD;
subpattern(in_dffe);
if (dff) {
ffD = dff;
clock = dffclock;
- if (dffrstmux) {
- ffDrstmux = dffrstmux;
- ffDrstpol = dffrstpol;
- }
- if (dffcemux) {
- ffDcemux = dffcemux;
- ffDcepol = dffcepol;
- }
sigD = dffD;
}
}
endcode
// (7) Match 'P' output that exclusively drives an MREG
-code argD ffM ffMcemux ffMrstmux ffMcepol ffMrstpol sigM sigP clock
+code argD ffM sigM sigP clock
if (param(dsp, \MREG).as_int() == 0 && nusers(sigM) == 2) {
argD = sigM;
subpattern(out_dffe);
if (dff) {
ffM = dff;
clock = dffclock;
- if (dffrstmux) {
- ffMrstmux = dffrstmux;
- ffMrstpol = dffrstpol;
- }
- if (dffcemux) {
- ffMcemux = dffcemux;
- ffMcepol = dffcepol;
- }
sigM = dffQ;
}
}
@@ -303,9 +243,7 @@ match postAdd
select postAdd->type.in($add)
select GetSize(port(postAdd, \Y)) <= 48
choice <IdString> AB {\A, \B}
- select nusers(port(postAdd, AB)) <= 3
- filter ffMcemux || nusers(port(postAdd, AB)) == 2
- filter !ffMcemux || nusers(port(postAdd, AB)) == 3
+ select nusers(port(postAdd, AB)) == 2
index <SigBit> port(postAdd, AB)[0] === sigP[0]
filter GetSize(port(postAdd, AB)) >= GetSize(sigP)
@@ -325,25 +263,14 @@ code sigC sigP
endcode
// (9) Match 'P' output that exclusively drives a PREG
-code argD ffP ffPcemux ffPrstmux ffPcepol ffPrstpol sigP clock
+code argD ffP sigP clock
if (param(dsp, \PREG).as_int() == 0) {
- int users = 2;
- // If ffMcemux and no postAdd new-value net must have three users: ffMcemux, ffM and ffPcemux
- if (ffMcemux && !postAdd) users++;
- if (nusers(sigP) == users) {
+ if (nusers(sigP) == 2) {
argD = sigP;
subpattern(out_dffe);
if (dff) {
ffP = dff;
clock = dffclock;
- if (dffrstmux) {
- ffPrstmux = dffrstmux;
- ffPrstpol = dffrstpol;
- }
- if (dffcemux) {
- ffPcemux = dffcemux;
- ffPcepol = dffcepol;
- }
sigP = dffQ;
}
}
@@ -387,26 +314,13 @@ endcode
// #######################
// Subpattern for matching against input registers, based on knowledge of the
-// 'Q' input. Typically, identifying registers with clock-enable and reset
-// capability would be a task would be handled by other Yosys passes such as
-// dff2dffe, but since DSP inference happens much before this, these patterns
-// have to be manually identified.
-// At a high level:
-// (1) Starting from a $dff cell that (partially or fully) drives the given
-// 'Q' argument
-// (2) Match for a $mux cell implementing synchronous reset semantics ---
-// one that exclusively drives the 'D' input of the $dff, with one of its
-// $mux inputs being fully zero
-// (3) Match for a $mux cell implement clock enable semantics --- one that
-// exclusively drives the 'D' input of the $dff (or the other input of
-// the reset $mux) and where one of this $mux's inputs is connected to
-// the 'Q' output of the $dff
+// 'Q' input.
subpattern in_dffe
-arg argD argQ clock
+arg argQ clock
code
dff = nullptr;
- if (GetSize(argQ) == 0)
+ if (argQ.empty())
reject;
for (const auto &c : argQ.chunks()) {
// Abandon matches when 'Q' is a constant
@@ -425,13 +339,14 @@ code
}
endcode
-// (1) Starting from a $dff cell that (partially or fully) drives the given
-// 'Q' argument
match ff
- select ff->type.in($dff)
+ select ff->type.in($dff, $dffe, $sdff, $sdffe)
// DSP48E1 does not support clock inversion
select param(ff, \CLK_POLARITY).as_bool()
+ // Check that reset value, if present, is fully 0.
+ filter ff->type.in($dff, $dffe) || param(ff, \SRST_VALUE).is_fully_zero()
+
slice offset GetSize(port(ff, \D))
index <SigBit> port(ff, \Q)[offset] === argQ[0]
@@ -440,82 +355,16 @@ match ff
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
filter clock == SigBit() || port(ff, \CLK) == clock
-
- set ffoffset offset
endmatch
-code argQ argD
+code argQ
SigSpec Q = port(ff, \Q);
dff = ff;
dffclock = port(ff, \CLK);
dffD = argQ;
- argD = port(ff, \D);
+ SigSpec D = port(ff, \D);
argQ = Q;
- dffD.replace(argQ, argD);
- // Only search for ffrstmux if dffD only
- // has two (ff, ffrstmux) users
- if (nusers(dffD) > 2)
- argD = SigSpec();
-endcode
-
-// (2) Match for a $mux cell implementing synchronous reset semantics ---
-// exclusively drives the 'D' input of the $dff, with one of the $mux
-// inputs being fully zero
-match ffrstmux
- if !argD.empty()
- select ffrstmux->type.in($mux)
- index <SigSpec> port(ffrstmux, \Y) === argD
-
- choice <IdString> BA {\B, \A}
- // DSP48E1 only supports reset to zero
- select port(ffrstmux, BA).is_fully_zero()
-
- define <bool> pol (BA == \B)
- set ffrstpol pol
- semioptional
-endmatch
-
-code argD
- if (ffrstmux) {
- dffrstmux = ffrstmux;
- dffrstpol = ffrstpol;
- argD = port(ffrstmux, ffrstpol ? \A : \B);
- dffD.replace(port(ffrstmux, \Y), argD);
-
- // Only search for ffcemux if argQ has at
- // least 3 users (ff, <upstream>, ffrstmux) and
- // dffD only has two (ff, ffrstmux)
- if (!(nusers(argQ) >= 3 && nusers(dffD) == 2))
- argD = SigSpec();
- }
- else
- dffrstmux = nullptr;
-endcode
-
-// (3) Match for a $mux cell implement clock enable semantics --- one that
-// exclusively drives the 'D' input of the $dff (or the other input of
-// the reset $mux) and where one of this $mux's inputs is connected to
-// the 'Q' output of the $dff
-match ffcemux
- if !argD.empty()
- select ffcemux->type.in($mux)
- index <SigSpec> port(ffcemux, \Y) === argD
- choice <IdString> AB {\A, \B}
- index <SigSpec> port(ffcemux, AB) === argQ
- define <bool> pol (AB == \A)
- set ffcepol pol
- semioptional
-endmatch
-
-code argD
- if (ffcemux) {
- dffcemux = ffcemux;
- dffcepol = ffcepol;
- argD = port(ffcemux, ffcepol ? \B : \A);
- dffD.replace(port(ffcemux, \Y), argD);
- }
- else
- dffcemux = nullptr;
+ dffD.replace(argQ, D);
endcode
// #######################
@@ -543,119 +392,26 @@ code
reject;
endcode
-// (1) Starting from an optional $mux cell that implements clock enable
-// semantics --- one where the given 'D' argument (partially or fully)
-// drives one of its two inputs
-match ffcemux
- select ffcemux->type.in($mux)
- // ffcemux output must have two users: ffcemux and ff.D
- select nusers(port(ffcemux, \Y)) == 2
-
- choice <IdString> AB {\A, \B}
- // keep-last-value net must have at least three users: ffcemux, ff, downstream sink(s)
- select nusers(port(ffcemux, AB)) >= 3
-
- slice offset GetSize(port(ffcemux, \Y))
- define <IdString> BA (AB == \A ? \B : \A)
- index <SigBit> port(ffcemux, BA)[offset] === argD[0]
-
- // Check that the rest of argD is present
- filter GetSize(port(ffcemux, BA)) >= offset + GetSize(argD)
- filter port(ffcemux, BA).extract(offset, GetSize(argD)) == argD
-
- set ffoffset offset
- define <bool> pol (AB == \A)
- set ffcepol pol
-
- semioptional
-endmatch
-
-code argD argQ
- dffcemux = ffcemux;
- if (ffcemux) {
- SigSpec BA = port(ffcemux, ffcepol ? \B : \A);
- SigSpec Y = port(ffcemux, \Y);
- argQ = argD;
- argD.replace(BA, Y);
- argQ.replace(BA, port(ffcemux, ffcepol ? \A : \B));
-
- dffcemux = ffcemux;
- dffcepol = ffcepol;
- }
-endcode
-
-// (2) Starting from, or continuing onto, another optional $mux cell that
-// implements synchronous reset semantics --- one where the given 'D'
-// argument (or the clock enable $mux output) drives one of its two inputs
-// and where the other input is fully zero
-match ffrstmux
- select ffrstmux->type.in($mux)
- // ffrstmux output must have two users: ffrstmux and ff.D
- select nusers(port(ffrstmux, \Y)) == 2
-
- choice <IdString> BA {\B, \A}
- // DSP48E1 only supports reset to zero
- select port(ffrstmux, BA).is_fully_zero()
-
- slice offset GetSize(port(ffrstmux, \Y))
- define <IdString> AB (BA == \B ? \A : \B)
- index <SigBit> port(ffrstmux, AB)[offset] === argD[0]
-
- // Check that offset is consistent
- filter !ffcemux || ffoffset == offset
- // Check that the rest of argD is present
- filter GetSize(port(ffrstmux, AB)) >= offset + GetSize(argD)
- filter port(ffrstmux, AB).extract(offset, GetSize(argD)) == argD
-
- set ffoffset offset
- define <bool> pol (AB == \A)
- set ffrstpol pol
-
- semioptional
-endmatch
-
-code argD argQ
- dffrstmux = ffrstmux;
- if (ffrstmux) {
- SigSpec AB = port(ffrstmux, ffrstpol ? \A : \B);
- SigSpec Y = port(ffrstmux, \Y);
- argD.replace(AB, Y);
-
- dffrstmux = ffrstmux;
- dffrstpol = ffrstpol;
- }
-endcode
-
-// (3) Match for a $dff cell (whose 'D' input is the 'D' argument, or the
-// output of the previous clock enable or reset $mux cells)
match ff
- select ff->type.in($dff)
+ select ff->type.in($dff, $dffe, $sdff, $sdffe)
// DSP48E1 does not support clock inversion
select param(ff, \CLK_POLARITY).as_bool()
slice offset GetSize(port(ff, \D))
index <SigBit> port(ff, \D)[offset] === argD[0]
- // Check that offset is consistent
- filter (!ffcemux && !ffrstmux) || ffoffset == offset
// Check that the rest of argD is present
filter GetSize(port(ff, \D)) >= offset + GetSize(argD)
filter port(ff, \D).extract(offset, GetSize(argD)) == argD
- // Check that FF.Q is connected to CE-mux
- filter !ffcemux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
filter clock == SigBit() || port(ff, \CLK) == clock
-
- set ffoffset offset
endmatch
code argQ
SigSpec D = port(ff, \D);
SigSpec Q = port(ff, \Q);
- if (!ffcemux) {
- argQ = argD;
- argQ.replace(D, Q);
- }
+ argQ = argD;
+ argQ.replace(D, Q);
// Abandon matches when 'Q' has a non-zero init attribute set
// (not supported by DSP48E1)
diff --git a/passes/pmgen/xilinx_dsp_CREG.pmg b/passes/pmgen/xilinx_dsp_CREG.pmg
index 42d4d1b9b..95379771a 100644
--- a/passes/pmgen/xilinx_dsp_CREG.pmg
+++ b/passes/pmgen/xilinx_dsp_CREG.pmg
@@ -26,17 +26,14 @@ pattern xilinx_dsp_packC
udata <std::function<SigSpec(const SigSpec&)>> unextend
state <SigBit> clock
state <SigSpec> sigC sigP
-state <bool> ffCcepol ffCrstpol
-state <Cell*> ffC ffCcemux ffCrstmux
+state <Cell*> ffC
// Variables used for subpatterns
state <SigSpec> argQ argD
-state <bool> ffcepol ffrstpol
state <int> ffoffset
udata <SigSpec> dffD dffQ
udata <SigBit> dffclock
-udata <Cell*> dff dffcemux dffrstmux
-udata <bool> dffcepol dffrstpol
+udata <Cell*> dff
// (1) Starting from a DSP48* cell that (a) doesn't have a CREG already,
// and (b) uses the 'C' port
@@ -80,20 +77,12 @@ endcode
// (2) Match the driver of the 'C' input to a possible $dff cell (CREG)
// (attached to at most two $mux cells that implement clock-enable or
// reset functionality, using the in_dffe subpattern)
-code argQ ffC ffCcemux ffCrstmux ffCcepol ffCrstpol sigC clock
+code argQ ffC sigC clock
argQ = sigC;
subpattern(in_dffe);
if (dff) {
ffC = dff;
clock = dffclock;
- if (dffrstmux) {
- ffCrstmux = dffrstmux;
- ffCrstpol = dffrstpol;
- }
- if (dffcemux) {
- ffCcemux = dffcemux;
- ffCcepol = dffcepol;
- }
sigC = dffD;
}
endcode
@@ -106,25 +95,14 @@ endcode
// #######################
// Subpattern for matching against input registers, based on knowledge of the
-// 'Q' input. Typically, identifying registers with clock-enable and reset
-// capability would be a task would be handled by other Yosys passes such as
-// dff2dffe, but since DSP inference happens much before this, these patterns
-// have to be manually identified.
-// At a high level:
-// (1) Starting from a $dff cell that (partially or fully) drives the given
-// 'Q' argument
-// (2) Match for a $mux cell implementing synchronous reset semantics ---
-// one that exclusively drives the 'D' input of the $dff, with one of its
-// $mux inputs being fully zero
-// (3) Match for a $mux cell implement clock enable semantics --- one that
-// exclusively drives the 'D' input of the $dff (or the other input of
-// the reset $mux) and where one of this $mux's inputs is connected to
-// the 'Q' output of the $dff
+// 'Q' input.
subpattern in_dffe
-arg argD argQ clock
+arg argQ clock
code
dff = nullptr;
+ if (argQ.empty())
+ reject;
for (const auto &c : argQ.chunks()) {
// Abandon matches when 'Q' is a constant
if (!c.wire)
@@ -135,19 +113,21 @@ code
// Abandon matches when 'Q' has a non-zero init attribute set
// (not supported by DSP48E1)
Const init = c.wire->attributes.at(\init, Const());
- for (auto b : init.extract(c.offset, c.width))
- if (b != State::Sx && b != State::S0)
- reject;
+ if (!init.empty())
+ for (auto b : init.extract(c.offset, c.width))
+ if (b != State::Sx && b != State::S0)
+ reject;
}
endcode
-// (1) Starting from a $dff cell that (partially or fully) drives the given
-// 'Q' argument
match ff
- select ff->type.in($dff)
+ select ff->type.in($dff, $dffe, $sdff, $sdffe)
// DSP48E1 does not support clock inversion
select param(ff, \CLK_POLARITY).as_bool()
+ // Check that reset value, if present, is fully 0.
+ filter ff->type.in($dff, $dffe) || param(ff, \SRST_VALUE).is_fully_zero()
+
slice offset GetSize(port(ff, \D))
index <SigBit> port(ff, \Q)[offset] === argQ[0]
@@ -156,80 +136,14 @@ match ff
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
filter clock == SigBit() || port(ff, \CLK) == clock
-
- set ffoffset offset
endmatch
-code argQ argD
+code argQ
SigSpec Q = port(ff, \Q);
dff = ff;
dffclock = port(ff, \CLK);
dffD = argQ;
- argD = port(ff, \D);
+ SigSpec D = port(ff, \D);
argQ = Q;
- dffD.replace(argQ, argD);
- // Only search for ffrstmux if dffD only
- // has two (ff, ffrstmux) users
- if (nusers(dffD) > 2)
- argD = SigSpec();
-endcode
-
-// (2) Match for a $mux cell implementing synchronous reset semantics ---
-// exclusively drives the 'D' input of the $dff, with one of the $mux
-// inputs being fully zero
-match ffrstmux
- if !argD.empty()
- select ffrstmux->type.in($mux)
- index <SigSpec> port(ffrstmux, \Y) === argD
-
- choice <IdString> BA {\B, \A}
- // DSP48E1 only supports reset to zero
- select port(ffrstmux, BA).is_fully_zero()
-
- define <bool> pol (BA == \B)
- set ffrstpol pol
- semioptional
-endmatch
-
-code argD
- if (ffrstmux) {
- dffrstmux = ffrstmux;
- dffrstpol = ffrstpol;
- argD = port(ffrstmux, ffrstpol ? \A : \B);
- dffD.replace(port(ffrstmux, \Y), argD);
-
- // Only search for ffcemux if argQ has at
- // least 3 users (ff, <upstream>, ffrstmux) and
- // dffD only has two (ff, ffrstmux)
- if (!(nusers(argQ) >= 3 && nusers(dffD) == 2))
- argD = SigSpec();
- }
- else
- dffrstmux = nullptr;
-endcode
-
-// (3) Match for a $mux cell implement clock enable semantics --- one that
-// exclusively drives the 'D' input of the $dff (or the other input of
-// the reset $mux) and where one of this $mux's inputs is connected to
-// the 'Q' output of the $dff
-match ffcemux
- if !argD.empty()
- select ffcemux->type.in($mux)
- index <SigSpec> port(ffcemux, \Y) === argD
- choice <IdString> AB {\A, \B}
- index <SigSpec> port(ffcemux, AB) === argQ
- define <bool> pol (AB == \A)
- set ffcepol pol
- semioptional
-endmatch
-
-code argD
- if (ffcemux) {
- dffcemux = ffcemux;
- dffcepol = ffcepol;
- argD = port(ffcemux, ffcepol ? \B : \A);
- dffD.replace(port(ffcemux, \Y), argD);
- }
- else
- dffcemux = nullptr;
+ dffD.replace(argQ, D);
endcode
diff --git a/passes/pmgen/xilinx_dsp_cascade.pmg b/passes/pmgen/xilinx_dsp_cascade.pmg
index 8babb88e6..06601554c 100644
--- a/passes/pmgen/xilinx_dsp_cascade.pmg
+++ b/passes/pmgen/xilinx_dsp_cascade.pmg
@@ -51,12 +51,10 @@ state <int> AREG BREG
// Variables used for subpatterns
state <SigSpec> argQ argD
-state <bool> ffcepol ffrstpol
state <int> ffoffset
udata <SigSpec> dffD dffQ
udata <SigBit> dffclock
-udata <Cell*> dff dffcemux dffrstmux
-udata <bool> dffcepol dffrstpol
+udata <Cell*> dff
code
#define MAX_DSP_CASCADE 20
@@ -254,9 +252,9 @@ code argQ clock AREG
clock = port(prev, \CLK);
subpattern(in_dffe);
if (dff) {
- if (!dffrstmux && port(prev, \RSTA, State::S0) != State::S0)
+ if (!dff->type.in($sdff, $sdffe) && port(prev, \RSTA, State::S0) != State::S0)
goto reject_AREG;
- if (dffrstmux && port(dffrstmux, \S) != port(prev, \RSTA, State::S0))
+ if (dff->type.in($sdff, $sdffe) && (port(dff, \SRST) != port(prev, \RSTA, State::S0) || !param(dff, \SRST_POLARITY).as_bool()))
goto reject_AREG;
IdString CEA;
if (param(prev, \AREG) == 1)
@@ -264,9 +262,9 @@ code argQ clock AREG
else if (param(prev, \AREG) == 2)
CEA = \CEA1;
else log_abort();
- if (!dffcemux && port(prev, CEA, State::S0) != State::S1)
+ if (!dff->type.in($dffe, $sdffe) && port(prev, CEA, State::S0) != State::S1)
goto reject_AREG;
- if (dffcemux && port(dffcemux, \S) != port(prev, CEA, State::S0))
+ if (dff->type.in($dffe, $sdffe) && (port(dff, \EN) != port(prev, CEA, State::S0) || !param(dff, \EN_POLARITY).as_bool()))
goto reject_AREG;
if (dffD == unextend(port(prev, \A)))
AREG = 1;
@@ -295,9 +293,9 @@ code argQ clock BREG
clock = port(prev, \CLK);
subpattern(in_dffe);
if (dff) {
- if (!dffrstmux && port(prev, \RSTB, State::S0) != State::S0)
+ if (!dff->type.in($sdff, $sdffe) && port(prev, \RSTB, State::S0) != State::S0)
goto reject_BREG;
- if (dffrstmux && port(dffrstmux, \S) != port(prev, \RSTB, State::S0))
+ if (dff->type.in($sdff, $sdffe) && (port(dff, \SRST) != port(prev, \RSTB, State::S0) || !param(dff, \SRST_POLARITY).as_bool()))
goto reject_BREG;
IdString CEB;
if (next->type.in(\DSP48A, \DSP48A1))
@@ -310,9 +308,9 @@ code argQ clock BREG
else log_abort();
}
else log_abort();
- if (!dffcemux && port(prev, CEB, State::S0) != State::S1)
+ if (!dff->type.in($dffe, $sdffe) && port(prev, CEB, State::S0) != State::S1)
goto reject_BREG;
- if (dffcemux && port(dffcemux, \S) != port(prev, CEB, State::S0))
+ if (dff->type.in($dffe, $sdffe) && (port(dff, \EN) != port(prev, CEB, State::S0) || !param(dff, \EN_POLARITY).as_bool()))
goto reject_BREG;
if (dffD == unextend(port(prev, \B))) {
if (next->type.in(\DSP48A, \DSP48A1) && param(prev, \B0REG) != 0)
@@ -357,25 +355,14 @@ endcode
// #######################
// Subpattern for matching against input registers, based on knowledge of the
-// 'Q' input. Typically, identifying registers with clock-enable and reset
-// capability would be a task would be handled by other Yosys passes such as
-// dff2dffe, but since DSP inference happens much before this, these patterns
-// have to be manually identified.
-// At a high level:
-// (1) Starting from a $dff cell that (partially or fully) drives the given
-// 'Q' argument
-// (2) Match for a $mux cell implementing synchronous reset semantics ---
-// one that exclusively drives the 'D' input of the $dff, with one of its
-// $mux inputs being fully zero
-// (3) Match for a $mux cell implement clock enable semantics --- one that
-// exclusively drives the 'D' input of the $dff (or the other input of
-// the reset $mux) and where one of this $mux's inputs is connected to
-// the 'Q' output of the $dff
+// 'Q' input.
subpattern in_dffe
-arg argD argQ clock
+arg argQ clock
code
dff = nullptr;
+ if (argQ.empty())
+ reject;
for (const auto &c : argQ.chunks()) {
// Abandon matches when 'Q' is a constant
if (!c.wire)
@@ -386,19 +373,21 @@ code
// Abandon matches when 'Q' has a non-zero init attribute set
// (not supported by DSP48E1)
Const init = c.wire->attributes.at(\init, Const());
- for (auto b : init.extract(c.offset, c.width))
- if (b != State::Sx && b != State::S0)
- reject;
+ if (!init.empty())
+ for (auto b : init.extract(c.offset, c.width))
+ if (b != State::Sx && b != State::S0)
+ reject;
}
endcode
-// (1) Starting from a $dff cell that (partially or fully) drives the given
-// 'Q' argument
match ff
- select ff->type.in($dff)
+ select ff->type.in($dff, $dffe, $sdff, $sdffe)
// DSP48E1 does not support clock inversion
select param(ff, \CLK_POLARITY).as_bool()
+ // Check that reset value, if present, is fully 0.
+ filter ff->type.in($dff, $dffe) || param(ff, \SRST_VALUE).is_fully_zero()
+
slice offset GetSize(port(ff, \D))
index <SigBit> port(ff, \Q)[offset] === argQ[0]
@@ -407,80 +396,14 @@ match ff
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
filter clock == SigBit() || port(ff, \CLK) == clock
-
- set ffoffset offset
endmatch
-code argQ argD
+code argQ
SigSpec Q = port(ff, \Q);
dff = ff;
dffclock = port(ff, \CLK);
dffD = argQ;
- argD = port(ff, \D);
+ SigSpec D = port(ff, \D);
argQ = Q;
- dffD.replace(argQ, argD);
- // Only search for ffrstmux if dffD only
- // has two (ff, ffrstmux) users
- if (nusers(dffD) > 2)
- argD = SigSpec();
-endcode
-
-// (2) Match for a $mux cell implementing synchronous reset semantics ---
-// exclusively drives the 'D' input of the $dff, with one of the $mux
-// inputs being fully zero
-match ffrstmux
- if !argD.empty()
- select ffrstmux->type.in($mux)
- index <SigSpec> port(ffrstmux, \Y) === argD
-
- choice <IdString> BA {\B, \A}
- // DSP48E1 only supports reset to zero
- select port(ffrstmux, BA).is_fully_zero()
-
- define <bool> pol (BA == \B)
- set ffrstpol pol
- semioptional
-endmatch
-
-code argD
- if (ffrstmux) {
- dffrstmux = ffrstmux;
- dffrstpol = ffrstpol;
- argD = port(ffrstmux, ffrstpol ? \A : \B);
- dffD.replace(port(ffrstmux, \Y), argD);
-
- // Only search for ffcemux if argQ has at
- // least 3 users (ff, <upstream>, ffrstmux) and
- // dffD only has two (ff, ffrstmux)
- if (!(nusers(argQ) >= 3 && nusers(dffD) == 2))
- argD = SigSpec();
- }
- else
- dffrstmux = nullptr;
-endcode
-
-// (3) Match for a $mux cell implement clock enable semantics --- one that
-// exclusively drives the 'D' input of the $dff (or the other input of
-// the reset $mux) and where one of this $mux's inputs is connected to
-// the 'Q' output of the $dff
-match ffcemux
- if !argD.empty()
- select ffcemux->type.in($mux)
- index <SigSpec> port(ffcemux, \Y) === argD
- choice <IdString> AB {\A, \B}
- index <SigSpec> port(ffcemux, AB) === argQ
- define <bool> pol (AB == \A)
- set ffcepol pol
- semioptional
-endmatch
-
-code argD
- if (ffcemux) {
- dffcemux = ffcemux;
- dffcepol = ffcepol;
- argD = port(ffcemux, ffcepol ? \B : \A);
- dffD.replace(port(ffcemux, \Y), argD);
- }
- else
- dffcemux = nullptr;
+ dffD.replace(argQ, D);
endcode
diff --git a/passes/pmgen/xilinx_srl.cc b/passes/pmgen/xilinx_srl.cc
index b99653fb3..1410850c7 100644
--- a/passes/pmgen/xilinx_srl.cc
+++ b/passes/pmgen/xilinx_srl.cc
@@ -188,7 +188,7 @@ void run_variable(xilinx_srl_pm &pm)
struct XilinxSrlPass : public Pass {
XilinxSrlPass() : Pass("xilinx_srl", "Xilinx shift register extraction") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -212,7 +212,7 @@ struct XilinxSrlPass : public Pass {
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing XILINX_SRL pass (Xilinx shift register extraction).\n");
diff --git a/passes/proc/proc.cc b/passes/proc/proc.cc
index a5b4a3112..09cf0af82 100644
--- a/passes/proc/proc.cc
+++ b/passes/proc/proc.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct ProcPass : public Pass {
ProcPass() : Pass("proc", "translate processes to netlists") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -50,6 +50,9 @@ struct ProcPass : public Pass {
log("\n");
log("The following options are supported:\n");
log("\n");
+ log(" -nomux\n");
+ log(" Will omit the proc_mux pass.\n");
+ log("\n");
log(" -global_arst [!]<netname>\n");
log(" This option is passed through to proc_arst.\n");
log("\n");
@@ -58,10 +61,11 @@ struct ProcPass : public Pass {
log(" executed in -ifx mode.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::string global_arst;
bool ifxmode = false;
+ bool nomux = false;
log_header(design, "Executing PROC pass (convert processes to netlists).\n");
log_push();
@@ -69,6 +73,10 @@ struct ProcPass : public Pass {
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
+ if (args[argidx] == "-nomux") {
+ nomux = true;
+ continue;
+ }
if (args[argidx] == "-global_arst" && argidx+1 < args.size()) {
global_arst = args[++argidx];
continue;
@@ -90,7 +98,8 @@ struct ProcPass : public Pass {
Pass::call(design, "proc_arst");
else
Pass::call(design, "proc_arst -global_arst " + global_arst);
- Pass::call(design, ifxmode ? "proc_mux -ifx" : "proc_mux");
+ if (!nomux)
+ Pass::call(design, ifxmode ? "proc_mux -ifx" : "proc_mux");
Pass::call(design, "proc_dlatch");
Pass::call(design, "proc_dff");
Pass::call(design, "proc_clean");
diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc
index e400fcb72..16db461b2 100644
--- a/passes/proc/proc_arst.cc
+++ b/passes/proc/proc_arst.cc
@@ -203,7 +203,7 @@ restart_proc_arst:
struct ProcArstPass : public Pass {
ProcArstPass() : Pass("proc_arst", "detect asynchronous resets") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -221,7 +221,7 @@ struct ProcArstPass : public Pass {
log(" in the 'init' attribute on the net.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::string global_arst;
bool global_arst_neg = false;
diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc
index 114c6ab03..5e78b7316 100644
--- a/passes/proc/proc_clean.cc
+++ b/passes/proc/proc_clean.cc
@@ -166,7 +166,7 @@ void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count, bool
struct ProcCleanPass : public Pass {
ProcCleanPass() : Pass("proc_clean", "remove empty parts of processes") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -179,7 +179,7 @@ struct ProcCleanPass : public Pass {
log("if it contains only empty structures.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
int total_count = 0;
bool quiet = false;
diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc
index 59cc5bd65..e320a72a6 100644
--- a/passes/proc/proc_dff.cc
+++ b/passes/proc/proc_dff.cc
@@ -370,7 +370,7 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
struct ProcDffPass : public Pass {
ProcDffPass() : Pass("proc_dff", "extract flip-flops from processes") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -380,7 +380,7 @@ struct ProcDffPass : public Pass {
log("d-type flip-flop cells.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing PROC_DFF pass (convert process syncs to FFs).\n");
diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc
index c9da1d1e3..7b8c05b21 100644
--- a/passes/proc/proc_dlatch.cc
+++ b/passes/proc/proc_dlatch.cc
@@ -19,6 +19,7 @@
#include "kernel/register.h"
#include "kernel/sigtools.h"
+#include "kernel/ffinit.h"
#include "kernel/consteval.h"
#include "kernel/log.h"
#include <sstream>
@@ -32,6 +33,7 @@ struct proc_dlatch_db_t
{
Module *module;
SigMap sigmap;
+ FfInitVals initvals;
pool<Cell*> generated_dlatches;
dict<Cell*, vector<SigBit>> mux_srcbits;
@@ -40,6 +42,8 @@ struct proc_dlatch_db_t
proc_dlatch_db_t(Module *module) : module(module), sigmap(module)
{
+ initvals.set(&sigmap, module);
+
for (auto cell : module->cells())
{
if (cell->type.in(ID($mux), ID($pmux)))
@@ -69,9 +73,11 @@ struct proc_dlatch_db_t
}
for (auto wire : module->wires())
+ {
if (wire->port_input)
for (auto bit : sigmap(wire))
sigusers[bit]++;
+ }
}
bool quickcheck(const SigSpec &haystack, const SigSpec &needle)
@@ -393,6 +399,13 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
else
log("No latch inferred for signal `%s.%s' from process `%s.%s'.\n",
db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str());
+ for (auto &bit : lhs) {
+ State val = db.initvals(bit);
+ if (db.initvals(bit) != State::Sx) {
+ log("Removing init bit %s for non-memory siginal `%s.%s` in process `%s.%s`.\n", log_signal(val), db.module->name.c_str(), log_signal(bit), db.module->name.c_str(), proc->name.c_str());
+ }
+ db.initvals.remove_init(bit);
+ }
db.module->connect(lhs, rhs);
offset += chunk.width;
}
@@ -434,7 +447,7 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
struct ProcDlatchPass : public Pass {
ProcDlatchPass() : Pass("proc_dlatch", "extract latches from processes") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -444,7 +457,7 @@ struct ProcDlatchPass : public Pass {
log("d-type latches.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing PROC_DLATCH pass (convert process syncs to latches).\n");
diff --git a/passes/proc/proc_init.cc b/passes/proc/proc_init.cc
index dc00019aa..eb323038d 100644
--- a/passes/proc/proc_init.cc
+++ b/passes/proc/proc_init.cc
@@ -86,7 +86,7 @@ void proc_init(RTLIL::Module *mod, SigMap &sigmap, RTLIL::Process *proc)
struct ProcInitPass : public Pass {
ProcInitPass() : Pass("proc_init", "convert initial block to init attributes") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -97,7 +97,7 @@ struct ProcInitPass : public Pass {
log("respective wire.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing PROC_INIT pass (extract init attributes).\n");
diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc
index 867ba1698..d20f34534 100644
--- a/passes/proc/proc_mux.cc
+++ b/passes/proc/proc_mux.cc
@@ -438,7 +438,7 @@ void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc, bool ifxmode)
struct ProcMuxPass : public Pass {
ProcMuxPass() : Pass("proc_mux", "convert decision trees to multiplexers") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -452,7 +452,7 @@ struct ProcMuxPass : public Pass {
log(" 'case' expressions and 'if' conditions.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool ifxmode = false;
log_header(design, "Executing PROC_MUX pass (convert decision trees to multiplexers).\n");
diff --git a/passes/proc/proc_prune.cc b/passes/proc/proc_prune.cc
index 8d11447f6..bd122b91f 100644
--- a/passes/proc/proc_prune.cc
+++ b/passes/proc/proc_prune.cc
@@ -125,7 +125,7 @@ struct PruneWorker
struct ProcPrunePass : public Pass {
ProcPrunePass() : Pass("proc_prune", "remove redundant assignments") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -135,7 +135,7 @@ struct ProcPrunePass : public Pass {
log("a later assignment to the same signal and removes them.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
int total_removed_count = 0, total_promoted_count = 0;
log_header(design, "Executing PROC_PRUNE pass (remove redundant assignments in processes).\n");
diff --git a/passes/proc/proc_rmdead.cc b/passes/proc/proc_rmdead.cc
index 6afaf25d1..ee91637ca 100644
--- a/passes/proc/proc_rmdead.cc
+++ b/passes/proc/proc_rmdead.cc
@@ -70,7 +70,7 @@ void proc_rmdead(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter)
struct ProcRmdeadPass : public Pass {
ProcRmdeadPass() : Pass("proc_rmdead", "eliminate dead trees in decision trees") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -79,7 +79,7 @@ struct ProcRmdeadPass : public Pass {
log("This pass identifies unreachable branches in decision trees and removes them.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing PROC_RMDEAD pass (remove dead branches from decision trees).\n");
diff --git a/passes/sat/assertpmux.cc b/passes/sat/assertpmux.cc
index 5bf2296ab..e9a10465e 100644
--- a/passes/sat/assertpmux.cc
+++ b/passes/sat/assertpmux.cc
@@ -181,7 +181,7 @@ struct AssertpmuxWorker
struct AssertpmuxPass : public Pass {
AssertpmuxPass() : Pass("assertpmux", "adds asserts for parallel muxes") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -199,7 +199,7 @@ struct AssertpmuxPass : public Pass {
log(" additional constraint and check the $pmux condition always.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool flag_noinit = false;
bool flag_always = false;
diff --git a/passes/sat/async2sync.cc b/passes/sat/async2sync.cc
index e344e2b5b..3fa5a614c 100644
--- a/passes/sat/async2sync.cc
+++ b/passes/sat/async2sync.cc
@@ -19,13 +19,15 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
+#include "kernel/ffinit.h"
+#include "kernel/ff.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct Async2syncPass : public Pass {
Async2syncPass() : Pass("async2sync", "convert async FF inputs to sync circuits") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -42,7 +44,7 @@ struct Async2syncPass : public Pass {
log("Currently only $adff, $dffsr, and $dlatch cells are supported by this pass.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
// bool flag_noinit = false;
@@ -62,169 +64,183 @@ struct Async2syncPass : public Pass {
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
- dict<SigBit, State> initbits;
- pool<SigBit> del_initbits;
-
- for (auto wire : module->wires())
- if (wire->attributes.count(ID::init) > 0)
- {
- Const initval = wire->attributes.at(ID::init);
- SigSpec initsig = sigmap(wire);
-
- for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++)
- if (initval[i] == State::S0 || initval[i] == State::S1)
- initbits[initsig[i]] = initval[i];
- }
+ FfInitVals initvals(&sigmap, module);
for (auto cell : vector<Cell*>(module->selected_cells()))
{
- if (cell->type.in(ID($adff)))
- {
- // bool clk_pol = cell->parameters[ID::CLK_POLARITY].as_bool();
- bool arst_pol = cell->parameters[ID::ARST_POLARITY].as_bool();
- Const arst_val = cell->parameters[ID::ARST_VALUE];
-
- // SigSpec sig_clk = cell->getPort(ID::CLK);
- SigSpec sig_arst = cell->getPort(ID::ARST);
- SigSpec sig_d = cell->getPort(ID::D);
- SigSpec sig_q = cell->getPort(ID::Q);
-
- log("Replacing %s.%s (%s): ARST=%s, D=%s, Q=%s\n",
- log_id(module), log_id(cell), log_id(cell->type),
- log_signal(sig_arst), log_signal(sig_d), log_signal(sig_q));
-
- Const init_val;
- for (int i = 0; i < GetSize(sig_q); i++) {
- SigBit bit = sigmap(sig_q[i]);
- init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx);
- del_initbits.insert(bit);
- }
+ if (!RTLIL::builtin_ff_cell_types().count(cell->type))
+ continue;
- Wire *new_d = module->addWire(NEW_ID, GetSize(sig_d));
- Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q));
- new_q->attributes[ID::init] = init_val;
+ FfData ff(&initvals, cell);
- if (arst_pol) {
- module->addMux(NEW_ID, sig_d, arst_val, sig_arst, new_d);
- module->addMux(NEW_ID, new_q, arst_val, sig_arst, sig_q);
- } else {
- module->addMux(NEW_ID, arst_val, sig_d, sig_arst, new_d);
- module->addMux(NEW_ID, arst_val, new_q, sig_arst, sig_q);
- }
-
- cell->setPort(ID::D, new_d);
- cell->setPort(ID::Q, new_q);
- cell->unsetPort(ID::ARST);
- cell->unsetParam(ID::ARST_POLARITY);
- cell->unsetParam(ID::ARST_VALUE);
- cell->type = ID($dff);
+ // Skip for $_FF_ and $ff cells.
+ if (ff.has_d && !ff.has_clk && !ff.has_en)
continue;
- }
- if (cell->type.in(ID($dffsr)))
+ if (ff.has_clk)
{
- // bool clk_pol = cell->parameters[ID::CLK_POLARITY].as_bool();
- bool set_pol = cell->parameters[ID::SET_POLARITY].as_bool();
- bool clr_pol = cell->parameters[ID::CLR_POLARITY].as_bool();
-
- // SigSpec sig_clk = cell->getPort(ID::CLK);
- SigSpec sig_set = cell->getPort(ID::SET);
- SigSpec sig_clr = cell->getPort(ID::CLR);
- SigSpec sig_d = cell->getPort(ID::D);
- SigSpec sig_q = cell->getPort(ID::Q);
-
- log("Replacing %s.%s (%s): SET=%s, CLR=%s, D=%s, Q=%s\n",
- log_id(module), log_id(cell), log_id(cell->type),
- log_signal(sig_set), log_signal(sig_clr), log_signal(sig_d), log_signal(sig_q));
-
- Const init_val;
- for (int i = 0; i < GetSize(sig_q); i++) {
- SigBit bit = sigmap(sig_q[i]);
- init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx);
- del_initbits.insert(bit);
+ if (!ff.has_sr && !ff.has_arst)
+ continue;
+
+ if (ff.has_sr) {
+ ff.unmap_ce_srst(module);
+
+ log("Replacing %s.%s (%s): SET=%s, CLR=%s, D=%s, Q=%s\n",
+ log_id(module), log_id(cell), log_id(cell->type),
+ log_signal(ff.sig_set), log_signal(ff.sig_clr), log_signal(ff.sig_d), log_signal(ff.sig_q));
+
+ initvals.remove_init(ff.sig_q);
+
+ Wire *new_d = module->addWire(NEW_ID, ff.width);
+ Wire *new_q = module->addWire(NEW_ID, ff.width);
+
+ SigSpec sig_set = ff.sig_set;
+ SigSpec sig_clr = ff.sig_clr;
+
+ if (!ff.pol_set) {
+ if (!ff.is_fine)
+ sig_set = module->Not(NEW_ID, sig_set);
+ else
+ sig_set = module->NotGate(NEW_ID, sig_set);
+ }
+
+ if (ff.pol_clr) {
+ if (!ff.is_fine)
+ sig_clr = module->Not(NEW_ID, sig_clr);
+ else
+ sig_clr = module->NotGate(NEW_ID, sig_clr);
+ }
+
+ if (!ff.is_fine) {
+ SigSpec tmp = module->Or(NEW_ID, ff.sig_d, sig_set);
+ module->addAnd(NEW_ID, tmp, sig_clr, new_d);
+
+ tmp = module->Or(NEW_ID, new_q, sig_set);
+ module->addAnd(NEW_ID, tmp, sig_clr, ff.sig_q);
+ } else {
+ SigSpec tmp = module->OrGate(NEW_ID, ff.sig_d, sig_set);
+ module->addAndGate(NEW_ID, tmp, sig_clr, new_d);
+
+ tmp = module->OrGate(NEW_ID, new_q, sig_set);
+ module->addAndGate(NEW_ID, tmp, sig_clr, ff.sig_q);
+ }
+
+ ff.sig_d = new_d;
+ ff.sig_q = new_q;
+ ff.has_sr = false;
+ } else if (ff.has_arst) {
+ ff.unmap_srst(module);
+
+ log("Replacing %s.%s (%s): ARST=%s, D=%s, Q=%s\n",
+ log_id(module), log_id(cell), log_id(cell->type),
+ log_signal(ff.sig_arst), log_signal(ff.sig_d), log_signal(ff.sig_q));
+
+ initvals.remove_init(ff.sig_q);
+
+ Wire *new_q = module->addWire(NEW_ID, ff.width);
+
+ if (ff.pol_arst) {
+ if (!ff.is_fine)
+ module->addMux(NEW_ID, new_q, ff.val_arst, ff.sig_arst, ff.sig_q);
+ else
+ module->addMuxGate(NEW_ID, new_q, ff.val_arst[0], ff.sig_arst, ff.sig_q);
+ } else {
+ if (!ff.is_fine)
+ module->addMux(NEW_ID, ff.val_arst, new_q, ff.sig_arst, ff.sig_q);
+ else
+ module->addMuxGate(NEW_ID, ff.val_arst[0], new_q, ff.sig_arst, ff.sig_q);
+ }
+
+ ff.sig_q = new_q;
+ ff.has_arst = false;
+ ff.has_srst = true;
+ ff.val_srst = ff.val_arst;
+ ff.sig_srst = ff.sig_arst;
+ ff.pol_srst = ff.pol_arst;
}
-
- Wire *new_d = module->addWire(NEW_ID, GetSize(sig_d));
- Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q));
- new_q->attributes[ID::init] = init_val;
-
- if (!set_pol)
- sig_set = module->Not(NEW_ID, sig_set);
-
- if (clr_pol)
- sig_clr = module->Not(NEW_ID, sig_clr);
-
- SigSpec tmp = module->Or(NEW_ID, sig_d, sig_set);
- module->addAnd(NEW_ID, tmp, sig_clr, new_d);
-
- tmp = module->Or(NEW_ID, new_q, sig_set);
- module->addAnd(NEW_ID, tmp, sig_clr, sig_q);
-
- cell->setPort(ID::D, new_d);
- cell->setPort(ID::Q, new_q);
- cell->unsetPort(ID::SET);
- cell->unsetPort(ID::CLR);
- cell->unsetParam(ID::SET_POLARITY);
- cell->unsetParam(ID::CLR_POLARITY);
- cell->type = ID($dff);
- continue;
}
-
- if (cell->type.in(ID($dlatch)))
+ else
{
- bool en_pol = cell->parameters[ID::EN_POLARITY].as_bool();
-
- SigSpec sig_en = cell->getPort(ID::EN);
- SigSpec sig_d = cell->getPort(ID::D);
- SigSpec sig_q = cell->getPort(ID::Q);
-
+ // Latch.
log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
log_id(module), log_id(cell), log_id(cell->type),
- log_signal(sig_en), log_signal(sig_d), log_signal(sig_q));
-
- Const init_val;
- for (int i = 0; i < GetSize(sig_q); i++) {
- SigBit bit = sigmap(sig_q[i]);
- init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx);
- del_initbits.insert(bit);
+ log_signal(ff.sig_en), log_signal(ff.sig_d), log_signal(ff.sig_q));
+
+ initvals.remove_init(ff.sig_q);
+
+ Wire *new_q = module->addWire(NEW_ID, ff.width);
+ Wire *new_d;
+
+ if (ff.has_d) {
+ new_d = module->addWire(NEW_ID, ff.width);
+ if (ff.pol_en) {
+ if (!ff.is_fine)
+ module->addMux(NEW_ID, new_q, ff.sig_d, ff.sig_en, new_d);
+ else
+ module->addMuxGate(NEW_ID, new_q, ff.sig_d, ff.sig_en, new_d);
+ } else {
+ if (!ff.is_fine)
+ module->addMux(NEW_ID, ff.sig_d, new_q, ff.sig_en, new_d);
+ else
+ module->addMuxGate(NEW_ID, ff.sig_d, new_q, ff.sig_en, new_d);
+ }
+ } else {
+ new_d = new_q;
}
- Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q));
- new_q->attributes[ID::init] = init_val;
-
- if (en_pol) {
- module->addMux(NEW_ID, new_q, sig_d, sig_en, sig_q);
+ if (ff.has_sr) {
+ SigSpec sig_set = ff.sig_set;
+ SigSpec sig_clr = ff.sig_clr;
+
+ if (!ff.pol_set) {
+ if (!ff.is_fine)
+ sig_set = module->Not(NEW_ID, sig_set);
+ else
+ sig_set = module->NotGate(NEW_ID, sig_set);
+ }
+
+ if (ff.pol_clr) {
+ if (!ff.is_fine)
+ sig_clr = module->Not(NEW_ID, sig_clr);
+ else
+ sig_clr = module->NotGate(NEW_ID, sig_clr);
+ }
+
+ if (!ff.is_fine) {
+ SigSpec tmp = module->Or(NEW_ID, new_d, sig_set);
+ module->addAnd(NEW_ID, tmp, sig_clr, ff.sig_q);
+ } else {
+ SigSpec tmp = module->OrGate(NEW_ID, new_d, sig_set);
+ module->addAndGate(NEW_ID, tmp, sig_clr, ff.sig_q);
+ }
+ } else if (ff.has_arst) {
+ if (ff.pol_arst) {
+ if (!ff.is_fine)
+ module->addMux(NEW_ID, new_d, ff.val_arst, ff.sig_arst, ff.sig_q);
+ else
+ module->addMuxGate(NEW_ID, new_d, ff.val_arst[0], ff.sig_arst, ff.sig_q);
+ } else {
+ if (!ff.is_fine)
+ module->addMux(NEW_ID, ff.val_arst, new_d, ff.sig_arst, ff.sig_q);
+ else
+ module->addMuxGate(NEW_ID, ff.val_arst[0], new_d, ff.sig_arst, ff.sig_q);
+ }
} else {
- module->addMux(NEW_ID, sig_d, new_q, sig_en, sig_q);
+ module->connect(ff.sig_q, new_d);
}
- cell->setPort(ID::D, sig_q);
- cell->setPort(ID::Q, new_q);
- cell->unsetPort(ID::EN);
- cell->unsetParam(ID::EN_POLARITY);
- cell->type = ID($ff);
- continue;
+ ff.sig_d = new_d;
+ ff.sig_q = new_q;
+ ff.has_en = false;
+ ff.has_arst = false;
+ ff.has_sr = false;
+ ff.has_d = true;
}
- }
- for (auto wire : module->wires())
- if (wire->attributes.count(ID::init) > 0)
- {
- bool delete_initattr = true;
- Const initval = wire->attributes.at(ID::init);
- SigSpec initsig = sigmap(wire);
-
- for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++)
- if (del_initbits.count(initsig[i]) > 0)
- initval[i] = State::Sx;
- else if (initval[i] != State::Sx)
- delete_initattr = false;
-
- if (delete_initattr)
- wire->attributes.erase(ID::init);
- else
- wire->attributes.at(ID::init) = initval;
- }
+ IdString name = cell->name;
+ module->remove(cell);
+ ff.emit(module, name);
+ }
}
}
} Async2syncPass;
diff --git a/passes/sat/clk2fflogic.cc b/passes/sat/clk2fflogic.cc
index 1e155e52c..cbf7c5435 100644
--- a/passes/sat/clk2fflogic.cc
+++ b/passes/sat/clk2fflogic.cc
@@ -19,13 +19,16 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
+#include "kernel/ffinit.h"
+#include "kernel/ff.h"
+#include "kernel/mem.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct Clk2fflogicPass : public Pass {
Clk2fflogicPass() : Pass("clk2fflogic", "convert clocked FFs to generic $ff cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -36,7 +39,31 @@ struct Clk2fflogicPass : public Pass {
log("multiple clocks.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ SigSpec wrap_async_control(Module *module, SigSpec sig, bool polarity) {
+ Wire *past_sig = module->addWire(NEW_ID, GetSize(sig));
+ module->addFf(NEW_ID, sig, past_sig);
+ if (polarity)
+ sig = module->Or(NEW_ID, sig, past_sig);
+ else
+ sig = module->And(NEW_ID, sig, past_sig);
+ if (polarity)
+ return sig;
+ else
+ return module->Not(NEW_ID, sig);
+ }
+ SigSpec wrap_async_control_gate(Module *module, SigSpec sig, bool polarity) {
+ Wire *past_sig = module->addWire(NEW_ID);
+ module->addFfGate(NEW_ID, sig, past_sig);
+ if (polarity)
+ sig = module->OrGate(NEW_ID, sig, past_sig);
+ else
+ sig = module->AndGate(NEW_ID, sig, past_sig);
+ if (polarity)
+ return sig;
+ else
+ return module->NotGate(NEW_ID, sig);
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
// bool flag_noinit = false;
@@ -56,348 +83,173 @@ struct Clk2fflogicPass : public Pass {
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
- dict<SigBit, State> initbits;
- pool<SigBit> del_initbits;
-
- for (auto wire : module->wires())
- if (wire->attributes.count(ID::init) > 0)
- {
- Const initval = wire->attributes.at(ID::init);
- SigSpec initsig = sigmap(wire);
+ FfInitVals initvals(&sigmap, module);
- for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++)
- if (initval[i] == State::S0 || initval[i] == State::S1)
- initbits[initsig[i]] = initval[i];
+ for (auto &mem : Mem::get_selected_memories(module))
+ {
+ for (int i = 0; i < GetSize(mem.rd_ports); i++) {
+ auto &port = mem.rd_ports[i];
+ if (port.clk_enable)
+ log_error("Read port %d of memory %s.%s is clocked. This is not supported by \"clk2fflogic\"! "
+ "Call \"memory\" with -nordff to avoid this error.\n", i, log_id(mem.memid), log_id(module));
}
- for (auto cell : vector<Cell*>(module->selected_cells()))
- {
- if (cell->type.in(ID($mem)))
+ for (int i = 0; i < GetSize(mem.wr_ports); i++)
{
- int abits = cell->getParam(ID::ABITS).as_int();
- int width = cell->getParam(ID::WIDTH).as_int();
- int rd_ports = cell->getParam(ID::RD_PORTS).as_int();
- int wr_ports = cell->getParam(ID::WR_PORTS).as_int();
-
- for (int i = 0; i < rd_ports; i++) {
- if (cell->getParam(ID::RD_CLK_ENABLE).extract(i).as_bool())
- log_error("Read port %d of memory %s.%s is clocked. This is not supported by \"clk2fflogic\"! "
- "Call \"memory\" with -nordff to avoid this error.\n", i, log_id(cell), log_id(module));
- }
-
- Const wr_clk_en_param = cell->getParam(ID::WR_CLK_ENABLE);
- Const wr_clk_pol_param = cell->getParam(ID::WR_CLK_POLARITY);
-
- SigSpec wr_clk_port = cell->getPort(ID::WR_CLK);
- SigSpec wr_en_port = cell->getPort(ID::WR_EN);
- SigSpec wr_addr_port = cell->getPort(ID::WR_ADDR);
- SigSpec wr_data_port = cell->getPort(ID::WR_DATA);
-
- for (int wport = 0; wport < wr_ports; wport++)
- {
- bool clken = wr_clk_en_param[wport] == State::S1;
- bool clkpol = wr_clk_pol_param[wport] == State::S1;
-
- if (!clken)
- continue;
+ auto &port = mem.wr_ports[i];
- SigBit clk = wr_clk_port[wport];
- SigSpec en = wr_en_port.extract(wport*width, width);
- SigSpec addr = wr_addr_port.extract(wport*abits, abits);
- SigSpec data = wr_data_port.extract(wport*width, width);
-
- log("Modifying write port %d on memory %s.%s: CLK=%s, A=%s, D=%s\n",
- wport, log_id(module), log_id(cell), log_signal(clk),
- log_signal(addr), log_signal(data));
-
- Wire *past_clk = module->addWire(NEW_ID);
- past_clk->attributes[ID::init] = clkpol ? State::S1 : State::S0;
- module->addFf(NEW_ID, clk, past_clk);
-
- SigSpec clock_edge_pattern;
-
- if (clkpol) {
- clock_edge_pattern.append(State::S0);
- clock_edge_pattern.append(State::S1);
- } else {
- clock_edge_pattern.append(State::S1);
- clock_edge_pattern.append(State::S0);
- }
+ if (!port.clk_enable)
+ continue;
- SigSpec clock_edge = module->Eqx(NEW_ID, {clk, SigSpec(past_clk)}, clock_edge_pattern);
+ log("Modifying write port %d on memory %s.%s: CLK=%s, A=%s, D=%s\n",
+ i, log_id(module), log_id(mem.memid), log_signal(port.clk),
+ log_signal(port.addr), log_signal(port.data));
- SigSpec en_q = module->addWire(NEW_ID, GetSize(en));
- module->addFf(NEW_ID, en, en_q);
-
- SigSpec addr_q = module->addWire(NEW_ID, GetSize(addr));
- module->addFf(NEW_ID, addr, addr_q);
-
- SigSpec data_q = module->addWire(NEW_ID, GetSize(data));
- module->addFf(NEW_ID, data, data_q);
+ Wire *past_clk = module->addWire(NEW_ID);
+ past_clk->attributes[ID::init] = port.clk_polarity ? State::S1 : State::S0;
+ module->addFf(NEW_ID, port.clk, past_clk);
- wr_clk_port[wport] = State::S0;
- wr_en_port.replace(wport*width, module->Mux(NEW_ID, Const(0, GetSize(en_q)), en_q, clock_edge));
- wr_addr_port.replace(wport*abits, addr_q);
- wr_data_port.replace(wport*width, data_q);
+ SigSpec clock_edge_pattern;
- wr_clk_en_param[wport] = State::S0;
- wr_clk_pol_param[wport] = State::S0;
+ if (port.clk_polarity) {
+ clock_edge_pattern.append(State::S0);
+ clock_edge_pattern.append(State::S1);
+ } else {
+ clock_edge_pattern.append(State::S1);
+ clock_edge_pattern.append(State::S0);
}
- cell->setParam(ID::WR_CLK_ENABLE, wr_clk_en_param);
- cell->setParam(ID::WR_CLK_POLARITY, wr_clk_pol_param);
+ SigSpec clock_edge = module->Eqx(NEW_ID, {port.clk, SigSpec(past_clk)}, clock_edge_pattern);
- cell->setPort(ID::WR_CLK, wr_clk_port);
- cell->setPort(ID::WR_EN, wr_en_port);
- cell->setPort(ID::WR_ADDR, wr_addr_port);
- cell->setPort(ID::WR_DATA, wr_data_port);
- }
-
- if (cell->type.in(ID($dlatch), ID($dlatchsr)))
- {
- bool enpol = cell->parameters[ID::EN_POLARITY].as_bool();
+ SigSpec en_q = module->addWire(NEW_ID, GetSize(port.en));
+ module->addFf(NEW_ID, port.en, en_q);
- SigSpec sig_en = cell->getPort(ID::EN);
- SigSpec sig_d = cell->getPort(ID::D);
- SigSpec sig_q = cell->getPort(ID::Q);
+ SigSpec addr_q = module->addWire(NEW_ID, GetSize(port.addr));
+ module->addFf(NEW_ID, port.addr, addr_q);
- log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
- log_id(module), log_id(cell), log_id(cell->type),
- log_signal(sig_en), log_signal(sig_d), log_signal(sig_q));
+ SigSpec data_q = module->addWire(NEW_ID, GetSize(port.data));
+ module->addFf(NEW_ID, port.data, data_q);
- Wire *past_q = module->addWire(NEW_ID, GetSize(sig_q));
- module->addFf(NEW_ID, sig_q, past_q);
+ port.clk = State::S0;
+ port.en = module->Mux(NEW_ID, Const(0, GetSize(en_q)), en_q, clock_edge);
+ port.addr = addr_q;
+ port.data = data_q;
- if (cell->type == ID($dlatch))
- {
- if (enpol)
- module->addMux(NEW_ID, past_q, sig_d, sig_en, sig_q);
- else
- module->addMux(NEW_ID, sig_d, past_q, sig_en, sig_q);
- }
- else
- {
- SigSpec t;
- if (enpol)
- t = module->Mux(NEW_ID, past_q, sig_d, sig_en);
- else
- t = module->Mux(NEW_ID, sig_d, past_q, sig_en);
+ port.clk_enable = false;
+ port.clk_polarity = false;
+ }
- SigSpec s = cell->getPort(ID::SET);
- if (!cell->parameters[ID::SET_POLARITY].as_bool())
- s = module->Not(NEW_ID, s);
- t = module->Or(NEW_ID, t, s);
+ mem.emit();
+ }
- SigSpec c = cell->getPort(ID::CLR);
- if (cell->parameters[ID::CLR_POLARITY].as_bool())
- c = module->Not(NEW_ID, c);
- module->addAnd(NEW_ID, t, c, sig_q);
- }
+ for (auto cell : vector<Cell*>(module->selected_cells()))
+ {
+ SigSpec qval;
+ if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
+ FfData ff(&initvals, cell);
- Const initval;
- bool assign_initval = false;
- for (int i = 0; i < GetSize(sig_d); i++) {
- SigBit qbit = sigmap(sig_q[i]);
- if (initbits.count(qbit)) {
- initval.bits.push_back(initbits.at(qbit));
- del_initbits.insert(qbit);
- } else
- initval.bits.push_back(State::Sx);
- if (initval.bits.back() != State::Sx)
- assign_initval = true;
+ if (ff.has_d && !ff.has_clk && !ff.has_en) {
+ // Already a $ff or $_FF_ cell.
+ continue;
}
- if (assign_initval)
- past_q->attributes[ID::init] = initval;
-
- module->remove(cell);
- continue;
- }
-
- bool word_dff = cell->type.in(ID($dff), ID($adff), ID($dffsr));
- if (word_dff || cell->type.in(ID($_DFF_N_), ID($_DFF_P_),
- ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
- ID($_DFF_PP0_), ID($_DFF_PP1_), ID($_DFF_PN0_), ID($_DFF_PN1_),
- ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
- ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_)))
- {
- bool clkpol;
- SigSpec clk;
- if (word_dff) {
- clkpol = cell->parameters[ID::CLK_POLARITY].as_bool();
- clk = cell->getPort(ID::CLK);
- }
- else {
- if (cell->type.in(ID($_DFF_P_), ID($_DFF_N_),
- ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
- ID($_DFF_PP0_), ID($_DFF_PP1_), ID($_DFF_PN0_), ID($_DFF_PN1_)))
- clkpol = cell->type[6] == 'P';
- else if (cell->type.in(ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
- ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_)))
- clkpol = cell->type[8] == 'P';
- else log_abort();
- clk = cell->getPort(ID::C);
+ Wire *past_q = module->addWire(NEW_ID, ff.width);
+ if (!ff.is_fine) {
+ module->addFf(NEW_ID, ff.sig_q, past_q);
+ } else {
+ module->addFfGate(NEW_ID, ff.sig_q, past_q);
}
+ if (!ff.val_init.is_fully_undef())
+ initvals.set_init(past_q, ff.val_init);
- Wire *past_clk = module->addWire(NEW_ID);
- past_clk->attributes[ID::init] = clkpol ? State::S1 : State::S0;
-
- if (word_dff)
- module->addFf(NEW_ID, clk, past_clk);
- else
- module->addFfGate(NEW_ID, clk, past_clk);
+ if (ff.has_clk) {
+ ff.unmap_ce_srst(module);
- SigSpec sig_d = cell->getPort(ID::D);
- SigSpec sig_q = cell->getPort(ID::Q);
+ Wire *past_clk = module->addWire(NEW_ID);
+ initvals.set_init(past_clk, ff.pol_clk ? State::S1 : State::S0);
- log("Replacing %s.%s (%s): CLK=%s, D=%s, Q=%s\n",
- log_id(module), log_id(cell), log_id(cell->type),
- log_signal(clk), log_signal(sig_d), log_signal(sig_q));
+ if (!ff.is_fine)
+ module->addFf(NEW_ID, ff.sig_clk, past_clk);
+ else
+ module->addFfGate(NEW_ID, ff.sig_clk, past_clk);
- SigSpec clock_edge_pattern;
+ log("Replacing %s.%s (%s): CLK=%s, D=%s, Q=%s\n",
+ log_id(module), log_id(cell), log_id(cell->type),
+ log_signal(ff.sig_clk), log_signal(ff.sig_d), log_signal(ff.sig_q));
- if (clkpol) {
- clock_edge_pattern.append(State::S0);
- clock_edge_pattern.append(State::S1);
- } else {
- clock_edge_pattern.append(State::S1);
- clock_edge_pattern.append(State::S0);
- }
-
- SigSpec clock_edge = module->Eqx(NEW_ID, {clk, SigSpec(past_clk)}, clock_edge_pattern);
+ SigSpec clock_edge_pattern;
- Wire *past_d = module->addWire(NEW_ID, GetSize(sig_d));
- Wire *past_q = module->addWire(NEW_ID, GetSize(sig_q));
- if (word_dff) {
- module->addFf(NEW_ID, sig_d, past_d);
- module->addFf(NEW_ID, sig_q, past_q);
- }
- else {
- module->addFfGate(NEW_ID, sig_d, past_d);
- module->addFfGate(NEW_ID, sig_q, past_q);
- }
+ if (ff.pol_clk) {
+ clock_edge_pattern.append(State::S0);
+ clock_edge_pattern.append(State::S1);
+ } else {
+ clock_edge_pattern.append(State::S1);
+ clock_edge_pattern.append(State::S0);
+ }
- if (cell->type == ID($adff))
- {
- SigSpec arst = cell->getPort(ID::ARST);
- SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge);
- Const rstval = cell->parameters[ID::ARST_VALUE];
+ SigSpec clock_edge = module->Eqx(NEW_ID, {ff.sig_clk, SigSpec(past_clk)}, clock_edge_pattern);
- Wire *past_arst = module->addWire(NEW_ID);
- module->addFf(NEW_ID, arst, past_arst);
- if (cell->parameters[ID::ARST_POLARITY].as_bool())
- arst = module->LogicOr(NEW_ID, arst, past_arst);
+ Wire *past_d = module->addWire(NEW_ID, ff.width);
+ if (!ff.is_fine)
+ module->addFf(NEW_ID, ff.sig_d, past_d);
else
- arst = module->LogicAnd(NEW_ID, arst, past_arst);
+ module->addFfGate(NEW_ID, ff.sig_d, past_d);
- if (cell->parameters[ID::ARST_POLARITY].as_bool())
- module->addMux(NEW_ID, qval, rstval, arst, sig_q);
- else
- module->addMux(NEW_ID, rstval, qval, arst, sig_q);
- }
- else
- if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
- ID($_DFF_PP0_), ID($_DFF_PP1_), ID($_DFF_PN0_), ID($_DFF_PN1_)))
- {
- SigSpec arst = cell->getPort(ID::R);
- SigSpec qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge);
- SigBit rstval = (cell->type[8] == '1');
-
- Wire *past_arst = module->addWire(NEW_ID);
- module->addFfGate(NEW_ID, arst, past_arst);
- if (cell->type[7] == 'P')
- arst = module->OrGate(NEW_ID, arst, past_arst);
- else
- arst = module->AndGate(NEW_ID, arst, past_arst);
+ if (!ff.val_init.is_fully_undef())
+ initvals.set_init(past_d, ff.val_init);
- if (cell->type[7] == 'P')
- module->addMuxGate(NEW_ID, qval, rstval, arst, sig_q);
+ if (!ff.is_fine)
+ qval = module->Mux(NEW_ID, past_q, past_d, clock_edge);
else
- module->addMuxGate(NEW_ID, rstval, qval, arst, sig_q);
- }
- else
- if (cell->type == ID($dffsr))
- {
- SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge);
- SigSpec setval = cell->getPort(ID::SET);
- SigSpec clrval = cell->getPort(ID::CLR);
+ qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge);
+ } else if (ff.has_d) {
- if (!cell->parameters[ID::SET_POLARITY].as_bool())
- setval = module->Not(NEW_ID, setval);
+ log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
+ log_id(module), log_id(cell), log_id(cell->type),
+ log_signal(ff.sig_en), log_signal(ff.sig_d), log_signal(ff.sig_q));
- if (cell->parameters[ID::CLR_POLARITY].as_bool())
- clrval = module->Not(NEW_ID, clrval);
+ SigSpec sig_en = wrap_async_control(module, ff.sig_en, ff.pol_en);
- qval = module->Or(NEW_ID, qval, setval);
- module->addAnd(NEW_ID, qval, clrval, sig_q);
- }
- else
- if (cell->type.in(ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
- ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_)))
- {
- SigSpec qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge);
- SigSpec setval = cell->getPort(ID::S);
- SigSpec clrval = cell->getPort(ID::R);
-
- if (cell->type[9] != 'P')
- setval = module->Not(NEW_ID, setval);
-
- if (cell->type[10] == 'P')
- clrval = module->Not(NEW_ID, clrval);
+ if (!ff.is_fine)
+ qval = module->Mux(NEW_ID, past_q, ff.sig_d, sig_en);
+ else
+ qval = module->MuxGate(NEW_ID, past_q, ff.sig_d, sig_en);
+ } else {
- qval = module->OrGate(NEW_ID, qval, setval);
- module->addAndGate(NEW_ID, qval, clrval, sig_q);
- }
- else if (cell->type == ID($dff))
- {
- module->addMux(NEW_ID, past_q, past_d, clock_edge, sig_q);
- }
- else
- {
- module->addMuxGate(NEW_ID, past_q, past_d, clock_edge, sig_q);
- }
+ log("Replacing %s.%s (%s): SET=%s, CLR=%s, Q=%s\n",
+ log_id(module), log_id(cell), log_id(cell->type),
+ log_signal(ff.sig_set), log_signal(ff.sig_clr), log_signal(ff.sig_q));
- Const initval;
- bool assign_initval = false;
- for (int i = 0; i < GetSize(sig_d); i++) {
- SigBit qbit = sigmap(sig_q[i]);
- if (initbits.count(qbit)) {
- initval.bits.push_back(initbits.at(qbit));
- del_initbits.insert(qbit);
- } else
- initval.bits.push_back(State::Sx);
- if (initval.bits.back() != State::Sx)
- assign_initval = true;
+ qval = past_q;
}
- if (assign_initval) {
- past_d->attributes[ID::init] = initval;
- past_q->attributes[ID::init] = initval;
+ if (ff.has_sr) {
+ SigSpec setval = wrap_async_control(module, ff.sig_set, ff.pol_set);
+ SigSpec clrval = wrap_async_control(module, ff.sig_clr, ff.pol_clr);
+ if (!ff.is_fine) {
+ clrval = module->Not(NEW_ID, clrval);
+ qval = module->Or(NEW_ID, qval, setval);
+ module->addAnd(NEW_ID, qval, clrval, ff.sig_q);
+ } else {
+ clrval = module->NotGate(NEW_ID, clrval);
+ qval = module->OrGate(NEW_ID, qval, setval);
+ module->addAndGate(NEW_ID, qval, clrval, ff.sig_q);
+ }
+ } else if (ff.has_arst) {
+ SigSpec arst = wrap_async_control(module, ff.sig_arst, ff.pol_arst);
+ if (!ff.is_fine)
+ module->addMux(NEW_ID, qval, ff.val_arst, arst, ff.sig_q);
+ else
+ module->addMuxGate(NEW_ID, qval, ff.val_arst[0], arst, ff.sig_q);
+ } else {
+ module->connect(ff.sig_q, qval);
}
+ initvals.remove_init(ff.sig_q);
module->remove(cell);
continue;
}
}
-
- for (auto wire : module->wires())
- if (wire->attributes.count(ID::init) > 0)
- {
- bool delete_initattr = true;
- Const initval = wire->attributes.at(ID::init);
- SigSpec initsig = sigmap(wire);
-
- for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++)
- if (del_initbits.count(initsig[i]) > 0)
- initval[i] = State::Sx;
- else if (initval[i] != State::Sx)
- delete_initattr = false;
-
- if (delete_initattr)
- wire->attributes.erase(ID::init);
- else
- wire->attributes.at(ID::init) = initval;
- }
}
}
diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc
index 26cc69211..6fc267d51 100644
--- a/passes/sat/cutpoint.cc
+++ b/passes/sat/cutpoint.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct CutpointPass : public Pass {
CutpointPass() : Pass("cutpoint", "adds formal cut points to the design") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -38,7 +38,7 @@ struct CutpointPass : public Pass {
log(" $anyseq cell and drive the cutpoint net from that\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool flag_undef = false;
@@ -126,15 +126,16 @@ struct CutpointPass : public Pass {
}
vector<Wire*> rewrite_wires;
- for (auto wire : module->wires()) {
- if (!wire->port_input)
- continue;
- int bit_count = 0;
- for (auto &bit : sigmap(wire))
- if (cutpoint_bits.count(bit))
- bit_count++;
- if (bit_count)
- rewrite_wires.push_back(wire);
+ for (auto id : module->ports) {
+ RTLIL::Wire *wire = module->wire(id);
+ if (wire->port_input) {
+ int bit_count = 0;
+ for (auto &bit : sigmap(wire))
+ if (cutpoint_bits.count(bit))
+ bit_count++;
+ if (bit_count)
+ rewrite_wires.push_back(wire);
+ }
}
for (auto wire : rewrite_wires) {
diff --git a/passes/sat/eval.cc b/passes/sat/eval.cc
index f910ea80d..085e7c5b8 100644
--- a/passes/sat/eval.cc
+++ b/passes/sat/eval.cc
@@ -359,7 +359,7 @@ struct VlogHammerReporter
struct EvalPass : public Pass {
EvalPass() : Pass("eval", "evaluate the circuit given an input") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -382,7 +382,7 @@ struct EvalPass : public Pass {
log(" then all output ports of the current module are used.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::vector<std::pair<std::string, std::string>> sets;
std::vector<std::string> shows, tables;
diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc
index 80ab82cd5..2c65821cf 100644
--- a/passes/sat/expose.cc
+++ b/passes/sat/expose.cc
@@ -217,7 +217,7 @@ RTLIL::Wire *add_new_wire(RTLIL::Module *module, RTLIL::IdString name, int width
struct ExposePass : public Pass {
ExposePass() : Pass("expose", "convert internal signals to module ports") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -254,7 +254,7 @@ struct ExposePass : public Pass {
log(" designator for the exposed signal.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool flag_shared = false;
bool flag_evert = false;
@@ -281,11 +281,15 @@ struct ExposePass : public Pass {
flag_dff = true;
continue;
}
- if (args[argidx] == "-cut" && !flag_input) {
+ if (args[argidx] == "-cut") {
+ if (flag_input)
+ log_cmd_error("Options -cut and -input are mutually exclusive.\n");
flag_cut = true;
continue;
}
- if (args[argidx] == "-input" && !flag_cut) {
+ if (args[argidx] == "-input") {
+ if (flag_cut)
+ log_cmd_error("Options -cut and -input are mutually exclusive.\n");
flag_input = true;
continue;
}
@@ -445,6 +449,8 @@ struct ExposePass : public Pass {
SigMap out_to_in_map;
+ std::map<RTLIL::Wire*, RTLIL::IdString> wire_map;
+
for (auto w : module->wires())
{
if (flag_shared) {
@@ -462,8 +468,7 @@ struct ExposePass : public Pass {
if (!w->port_input) {
w->port_input = true;
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(w->name));
- RTLIL::Wire *in_wire = module->addWire(NEW_ID, GetSize(w));
- out_to_in_map.add(w, in_wire);
+ wire_map[w] = NEW_ID;
}
}
else
@@ -474,15 +479,19 @@ struct ExposePass : public Pass {
}
if (flag_cut) {
- RTLIL::Wire *in_wire = add_new_wire(module, w->name.str() + sep + "i", w->width);
- in_wire->port_input = true;
- out_to_in_map.add(sigmap(w), in_wire);
+ wire_map[w] = w->name.str() + sep + "i";
}
}
}
if (flag_input)
{
+ for (auto &wm : wire_map)
+ {
+ RTLIL::Wire *in_wire = module->addWire(wm.second, GetSize(wm.first));
+ out_to_in_map.add(wm.first, in_wire);
+ }
+
for (auto cell : module->cells()) {
if (!ct.cell_known(cell->type))
continue;
@@ -497,6 +506,13 @@ struct ExposePass : public Pass {
if (flag_cut)
{
+ for (auto &wm : wire_map)
+ {
+ RTLIL::Wire *in_wire = add_new_wire(module, wm.second, wm.first->width);
+ in_wire->port_input = true;
+ out_to_in_map.add(sigmap(wm.first), in_wire);
+ }
+
for (auto cell : module->cells()) {
if (!ct.cell_known(cell->type))
continue;
diff --git a/passes/sat/fmcombine.cc b/passes/sat/fmcombine.cc
index 5066485aa..cb49edac3 100644
--- a/passes/sat/fmcombine.cc
+++ b/passes/sat/fmcombine.cc
@@ -114,8 +114,7 @@ struct FmcombineWorker
Cell *gold = import_prim_cell(cell, "_gold");
Cell *gate = import_prim_cell(cell, "_gate");
if (opts.initeq) {
- if (cell->type.in(ID($ff), ID($dff), ID($dffe),
- ID($dffsr), ID($adff), ID($dlatch), ID($dlatchsr))) {
+ if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
SigSpec gold_q = gold->getPort(ID::Q);
SigSpec gate_q = gate->getPort(ID::Q);
SigSpec en = module->Initstate(NEW_ID);
@@ -235,7 +234,7 @@ struct FmcombineWorker
struct FmcombinePass : public Pass {
FmcombinePass() : Pass("fmcombine", "combine two instances of a cell into one") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -272,7 +271,7 @@ struct FmcombinePass : public Pass {
log("If none of -fwd, -bwd, and -nop is given, then -fwd is used as default.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
opts_t opts;
Module *module = nullptr;
diff --git a/passes/sat/fminit.cc b/passes/sat/fminit.cc
index 555a28dc6..c72e62548 100644
--- a/passes/sat/fminit.cc
+++ b/passes/sat/fminit.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct FminitPass : public Pass {
FminitPass() : Pass("fminit", "set init values/sequences for formal") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -47,7 +47,7 @@ struct FminitPass : public Pass {
log(" Set clock for init sequences\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
vector<pair<string, vector<string>>> initdata;
vector<pair<string, string>> setdata;
diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc
index 5dfd7bd3f..762edfdfb 100644
--- a/passes/sat/freduce.cc
+++ b/passes/sat/freduce.cc
@@ -760,7 +760,7 @@ struct FreduceWorker
struct FreducePass : public Pass {
FreducePass() : Pass("freduce", "perform functional reduction") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -791,7 +791,7 @@ struct FreducePass : public Pass {
log("circuit that is analyzed.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
reduce_counter = 0;
reduce_stop_at = 0;
diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc
index aeece9b94..fe4a819f3 100644
--- a/passes/sat/miter.cc
+++ b/passes/sat/miter.cc
@@ -354,7 +354,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL
struct MiterPass : public Pass {
MiterPass() : Pass("miter", "automatically create a miter circuit") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -398,7 +398,7 @@ struct MiterPass : public Pass {
log(" call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
if (args.size() > 1 && args[1] == "-equiv") {
create_miter_equiv(this, args, design);
diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc
index af8ffca9e..95e0e0944 100644
--- a/passes/sat/mutate.cc
+++ b/passes/sat/mutate.cc
@@ -439,7 +439,7 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena
dict<SigBit, int> bit_user_cnt;
for (auto wire : module->wires()) {
- if (wire->name[0] == '\\' && wire->attributes.count(ID::src))
+ if (wire->name.isPublic() && wire->attributes.count(ID::src))
sigmap.add(wire);
}
@@ -468,7 +468,7 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena
}
if (!bit.wire->name[0] != !sigbit.wire->name[0]) {
- if (bit.wire->name[0] == '\\')
+ if (bit.wire->name.isPublic())
sigmap.add(bit);
continue;
}
@@ -493,7 +493,7 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena
entry.src.insert(s);
SigBit bit = sigmap(conn.second[i]);
- if (bit.wire && bit.wire->name[0] == '\\' && (cell->output(conn.first) || bit_user_cnt[bit] == 1)) {
+ if (bit.wire && bit.wire->name.isPublic() && (cell->output(conn.first) || bit_user_cnt[bit] == 1)) {
for (auto &s : bit.wire->get_strpool_attribute(ID::src))
entry.src.insert(s);
entry.wire = bit.wire->name;
@@ -726,7 +726,7 @@ void mutate_cnot(Design *design, const mutate_opts_t &opts, bool one)
struct MutatePass : public Pass {
MutatePass() : Pass("mutate", "generate or apply design mutations") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -790,7 +790,7 @@ struct MutatePass : public Pass {
log(" Ignored. (They are generated by -list for documentation purposes.)\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
mutate_opts_t opts;
string filename;
diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc
index d6dbf8ef4..6db7d4b64 100644
--- a/passes/sat/qbfsat.cc
+++ b/passes/sat/qbfsat.cc
@@ -1,4 +1,4 @@
-/*
+/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2020 Alberto Gonzalez <boqwxp@airmail.cc>
@@ -18,137 +18,20 @@
*/
#include "kernel/yosys.h"
-#include "kernel/celltypes.h"
#include "kernel/consteval.h"
-#include "kernel/log.h"
-#include "kernel/rtlil.h"
-#include "kernel/register.h"
-#include <algorithm>
+#include "qbfsat.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-struct QbfSolutionType {
- std::vector<std::string> stdout_lines;
- dict<std::string, std::string> hole_to_value;
- bool sat;
- bool unknown; //true if neither 'sat' nor 'unsat'
-
- QbfSolutionType() : sat(false), unknown(true) {}
-};
-
-struct QbfSolveOptions {
- bool specialize, specialize_from_file, write_solution, nocleanup, dump_final_smt2, assume_outputs, assume_neg;
- bool nooptimize, nobisection;
- bool sat, unsat, show_smtbmc;
- enum Solver{Z3, Yices, CVC4} solver;
- int timeout;
- std::string specialize_soln_file;
- std::string write_soln_soln_file;
- std::string dump_final_smt2_file;
- size_t argidx;
- QbfSolveOptions() : specialize(false), specialize_from_file(false), write_solution(false),
- nocleanup(false), dump_final_smt2(false), assume_outputs(false), assume_neg(false),
- nooptimize(false), nobisection(false), sat(false), unsat(false), show_smtbmc(false),
- solver(Yices), timeout(0), argidx(0) {};
-};
-
-std::string get_solver_name(const QbfSolveOptions &opt) {
- if (opt.solver == opt.Solver::Z3)
- return "z3";
- else if (opt.solver == opt.Solver::Yices)
- return "yices";
- else if (opt.solver == opt.Solver::CVC4)
- return "cvc4";
+static inline unsigned int difference(unsigned int a, unsigned int b) {
+ if (a < b)
+ return b - a;
else
- log_cmd_error("unknown solver specified.\n");
- return "";
+ return a - b;
}
-void recover_solution(QbfSolutionType &sol) {
- YS_REGEX_TYPE sat_regex = YS_REGEX_COMPILE("Status: PASSED");
- YS_REGEX_TYPE unsat_regex = YS_REGEX_COMPILE("Solver Error.*model is not available");
- YS_REGEX_TYPE unsat_regex2 = YS_REGEX_COMPILE("Status: FAILED");
- YS_REGEX_TYPE timeout_regex = YS_REGEX_COMPILE("No solution found! \\(timeout\\)");
- YS_REGEX_TYPE timeout_regex2 = YS_REGEX_COMPILE("No solution found! \\(interrupted\\)");
- YS_REGEX_TYPE unknown_regex = YS_REGEX_COMPILE("No solution found! \\(unknown\\)");
- YS_REGEX_TYPE unknown_regex2 = YS_REGEX_COMPILE("Unexpected EOF response from solver");
- YS_REGEX_TYPE memout_regex = YS_REGEX_COMPILE("Solver Error:.*error \"out of memory\"");
- YS_REGEX_TYPE hole_value_regex = YS_REGEX_COMPILE_WITH_SUBS("Value for anyconst in [a-zA-Z0-9_]* \\(([^:]*:[^\\)]*)\\): (.*)");
-#ifndef NDEBUG
- YS_REGEX_TYPE hole_loc_regex = YS_REGEX_COMPILE("[^:]*:[0-9]+.[0-9]+-[0-9]+.[0-9]+");
- YS_REGEX_TYPE hole_val_regex = YS_REGEX_COMPILE("[0-9]+");
-#endif
- YS_REGEX_MATCH_TYPE m;
- bool sat_regex_found = false;
- bool unsat_regex_found = false;
- dict<std::string, bool> hole_value_recovered;
- for (const std::string &x : sol.stdout_lines) {
- if(YS_REGEX_NS::regex_search(x, m, hole_value_regex)) {
- std::string loc = m[1].str();
- std::string val = m[2].str();
-#ifndef NDEBUG
- log_assert(YS_REGEX_NS::regex_search(loc, hole_loc_regex));
- log_assert(YS_REGEX_NS::regex_search(val, hole_val_regex));
-#endif
- sol.hole_to_value[loc] = val;
- }
- else if (YS_REGEX_NS::regex_search(x, sat_regex)) {
- sat_regex_found = true;
- sol.sat = true;
- sol.unknown = false;
- }
- else if (YS_REGEX_NS::regex_search(x, unsat_regex)) {
- unsat_regex_found = true;
- sol.sat = false;
- sol.unknown = false;
- }
- else if (YS_REGEX_NS::regex_search(x, memout_regex)) {
- sol.unknown = true;
- log_warning("solver ran out of memory\n");
- }
- else if (YS_REGEX_NS::regex_search(x, timeout_regex)) {
- sol.unknown = true;
- log_warning("solver timed out\n");
- }
- else if (YS_REGEX_NS::regex_search(x, timeout_regex2)) {
- sol.unknown = true;
- log_warning("solver timed out\n");
- }
- else if (YS_REGEX_NS::regex_search(x, unknown_regex)) {
- sol.unknown = true;
- log_warning("solver returned \"unknown\"\n");
- }
- else if (YS_REGEX_NS::regex_search(x, unsat_regex2)) {
- unsat_regex_found = true;
- sol.sat = false;
- sol.unknown = false;
- }
- else if (YS_REGEX_NS::regex_search(x, unknown_regex2)) {
- sol.unknown = true;
- }
- }
-#ifndef NDEBUG
- log_assert(!sol.unknown && sol.sat? sat_regex_found : true);
- log_assert(!sol.unknown && !sol.sat? unsat_regex_found : true);
-#endif
-}
-
-dict<std::string, std::string> get_hole_loc_name_map(RTLIL::Module *module, const QbfSolutionType &sol) {
- dict<std::string, std::string> hole_loc_to_name;
- for (auto cell : module->cells()) {
- std::string cell_src = cell->get_src_attribute();
- auto pos = sol.hole_to_value.find(cell_src);
- if (pos != sol.hole_to_value.end() && cell->type.in("$anyconst", "$anyseq")) {
- log_assert(hole_loc_to_name.find(pos->first) == hole_loc_to_name.end());
- hole_loc_to_name[pos->first] = cell->getPort(ID::Y).as_wire()->name.str();
- }
- }
-
- return hole_loc_to_name;
-}
-
-pool<std::string> validate_design_and_get_inputs(RTLIL::Module *module, const QbfSolveOptions &opt) {
+pool<std::string> validate_design_and_get_inputs(RTLIL::Module *module, bool assume_outputs) {
bool found_input = false;
bool found_hole = false;
bool found_1bit_output = false;
@@ -176,133 +59,108 @@ pool<std::string> validate_design_and_get_inputs(RTLIL::Module *module, const Qb
log_cmd_error("Did not find any existentially-quantified variables. Use 'sat' instead.\n");
if (!found_1bit_output && !found_assert_assume)
log_cmd_error("Did not find any single-bit outputs or $assert/$assume cells. Is this a miter circuit?\n");
- if (!found_assert_assume && !opt.assume_outputs)
+ if (!found_assert_assume && !assume_outputs)
log_cmd_error("Did not find any $assert/$assume cells. Single-bit outputs were found, but `-assume-outputs` was not specified.\n");
return input_wires;
}
-void write_solution(RTLIL::Module *module, const QbfSolutionType &sol, const std::string &file) {
- std::ofstream fout(file.c_str());
- if (!fout)
- log_cmd_error("could not open solution file for writing.\n");
+void specialize_from_file(RTLIL::Module *module, const std::string &file) {
+ YS_REGEX_TYPE hole_bit_assn_regex = YS_REGEX_COMPILE_WITH_SUBS("^(.+) ([0-9]+) ([^ ]+) \\[([0-9]+)] = ([01])$");
+ YS_REGEX_TYPE hole_assn_regex = YS_REGEX_COMPILE_WITH_SUBS("^(.+) ([0-9]+) ([^ ]+) = ([01])$"); //if no index specified
+ YS_REGEX_MATCH_TYPE bit_m, m;
+ dict<pool<std::string>, RTLIL::Cell*> anyconst_loc_to_cell;
+ dict<RTLIL::SigBit, RTLIL::State> hole_assignments;
- dict<std::string, std::string> hole_loc_to_name = get_hole_loc_name_map(module, sol);
- for(auto &x : sol.hole_to_value)
- fout << hole_loc_to_name[x.first] << "=" << x.second << std::endl;
-}
+ for (auto cell : module->cells())
+ if (cell->type == "$anyconst")
+ anyconst_loc_to_cell[cell->get_strpool_attribute(ID::src)] = cell;
-void specialize_from_file(RTLIL::Module *module, const std::string &file) {
- YS_REGEX_TYPE hole_assn_regex = YS_REGEX_COMPILE_WITH_SUBS("^(.*)=([01]+)$");
- YS_REGEX_MATCH_TYPE m;
- pool<RTLIL::Cell *> anyconsts_to_remove;
- dict<std::string, std::string> hole_name_to_value;
std::ifstream fin(file.c_str());
if (!fin)
log_cmd_error("could not read solution file.\n");
std::string buf;
while (std::getline(fin, buf)) {
- log_assert(YS_REGEX_NS::regex_search(buf, m, hole_assn_regex));
- std::string hole_name = m[1].str();
- std::string hole_value = m[2].str();
- hole_name_to_value[hole_name] = hole_value;
+ bool bit_assn = true;
+ if (!YS_REGEX_NS::regex_search(buf, bit_m, hole_bit_assn_regex)) {
+ bit_assn = false;
+ if (!YS_REGEX_NS::regex_search(buf, m, hole_assn_regex))
+ log_cmd_error("solution file is not formatted correctly: \"%s\"\n", buf.c_str());
+ }
+
+ std::string hole_loc = bit_assn? bit_m[1].str() : m[1].str();
+ unsigned int hole_bit = bit_assn? atoi(bit_m[2].str().c_str()) : atoi(m[2].str().c_str());
+ std::string hole_name = bit_assn? bit_m[3].str() : m[3].str();
+ unsigned int hole_offset = bit_assn? atoi(bit_m[4].str().c_str()) : 0;
+ RTLIL::State hole_value = bit_assn? (atoi(bit_m[5].str().c_str()) == 1? RTLIL::State::S1 : RTLIL::State::S0)
+ : (atoi(m[4].str().c_str()) == 1? RTLIL::State::S1 : RTLIL::State::S0);
+
+ //We have two options to identify holes. First, try to match wire names. If we can't find a matching wire,
+ //then try to find a cell with a matching location.
+ RTLIL::SigBit hole_sigbit;
+ if (module->wire(hole_name) != nullptr) {
+ RTLIL::Wire *hole_wire = module->wire(hole_name);
+ hole_sigbit = RTLIL::SigSpec(hole_wire)[hole_offset];
+ } else {
+ auto locs = split_tokens(hole_loc, "|");
+ pool<std::string> hole_loc_pool(locs.begin(), locs.end());
+ auto hole_cell_it = anyconst_loc_to_cell.find(hole_loc_pool);
+ if (hole_cell_it == anyconst_loc_to_cell.end())
+ log_cmd_error("cannot find matching wire name or $anyconst cell location for hole spec \"%s\"\n", buf.c_str());
+
+ RTLIL::Cell *hole_cell = hole_cell_it->second;
+ hole_sigbit = hole_cell->getPort(ID::Y)[hole_bit];
+ }
+ hole_assignments[hole_sigbit] = hole_value;
}
- for (auto cell : module->cells())
- if (cell->type == "$anyconst") {
- auto anyconst_port_y = cell->getPort(ID::Y).as_wire();
- if (anyconst_port_y == nullptr)
- continue;
- if (hole_name_to_value.find(anyconst_port_y->name.str()) != hole_name_to_value.end())
- anyconsts_to_remove.insert(cell);
- }
- for (auto cell : anyconsts_to_remove)
- module->remove(cell);
+ for (auto &it : anyconst_loc_to_cell)
+ module->remove(it.second);
- for (auto &it : hole_name_to_value) {
- std::string hole_name = it.first;
- std::string hole_value = it.second;
- RTLIL::Wire *wire = module->wire(hole_name);
-#ifndef NDEBUG
- log_assert(wire != nullptr);
- log_assert(wire->width > 0 && GetSize(hole_value) == wire->width);
-#endif
-
- log("Specializing %s from file with %s = %d'b%s.\n", module->name.c_str(), hole_name.c_str(), wire->width, hole_value.c_str());
- std::vector<RTLIL::SigBit> value_bv;
- value_bv.reserve(wire->width);
- for (char c : hole_value)
- value_bv.emplace_back(c == '1'? RTLIL::S1 : RTLIL::S0);
- std::reverse(value_bv.begin(), value_bv.end());
- module->connect(wire, value_bv);
+ for (auto &it : hole_assignments) {
+ RTLIL::SigSpec lhs(it.first);
+ RTLIL::SigSpec rhs(it.second);
+ log("Specializing %s from file with %s = %d.\n", module->name.c_str(), log_signal(it.first), it.second == RTLIL::State::S1? 1 : 0);
+ module->connect(lhs, rhs);
}
}
void specialize(RTLIL::Module *module, const QbfSolutionType &sol, bool quiet = false) {
- dict<std::string, std::string> hole_loc_to_name = get_hole_loc_name_map(module, sol);
+ auto hole_loc_idx_to_sigbit = sol.get_hole_loc_idx_sigbit_map(module);
pool<RTLIL::Cell *> anyconsts_to_remove;
for (auto cell : module->cells())
if (cell->type == "$anyconst")
- if (hole_loc_to_name.find(cell->get_src_attribute()) != hole_loc_to_name.end())
+ if (hole_loc_idx_to_sigbit.find(std::make_pair(cell->get_strpool_attribute(ID::src), 0)) != hole_loc_idx_to_sigbit.end())
anyconsts_to_remove.insert(cell);
for (auto cell : anyconsts_to_remove)
module->remove(cell);
for (auto &it : sol.hole_to_value) {
- std::string hole_loc = it.first;
- std::string hole_value = it.second;
-
-#ifndef NDEBUG
- auto pos = hole_loc_to_name.find(hole_loc);
- log_assert(pos != hole_loc_to_name.end());
-#endif
-
- std::string hole_name = hole_loc_to_name[hole_loc];
- RTLIL::Wire *wire = module->wire(hole_name);
-#ifndef NDEBUG
- log_assert(wire != nullptr);
- log_assert(wire->width > 0 && GetSize(hole_value) == wire->width);
-#endif
-
- if (!quiet)
- log("Specializing %s with %s = %d'b%s.\n", module->name.c_str(), hole_name.c_str(), wire->width, hole_value.c_str());
- std::vector<RTLIL::SigBit> value_bv;
- value_bv.reserve(wire->width);
- for (char c : hole_value)
- value_bv.emplace_back(c == '1'? RTLIL::S1 : RTLIL::S0);
- std::reverse(value_bv.begin(), value_bv.end());
- module->connect(wire, value_bv);
- }
-}
-
-void dump_model(RTLIL::Module *module, const QbfSolutionType &sol) {
- log("Satisfiable model:\n");
- dict<std::string, std::string> hole_loc_to_name = get_hole_loc_name_map(module, sol);
- for (auto &it : sol.hole_to_value) {
- std::string hole_loc = it.first;
+ pool<std::string> hole_loc = it.first;
std::string hole_value = it.second;
-#ifndef NDEBUG
- auto pos = hole_loc_to_name.find(hole_loc);
- log_assert(pos != hole_loc_to_name.end());
-#endif
-
- std::string hole_name = hole_loc_to_name[hole_loc];
- log("\t%s = %lu'b%s\n", hole_name.c_str(), hole_value.size(), hole_value.c_str());
- std::vector<RTLIL::SigBit> value_bv;
- value_bv.reserve(hole_value.size());
- for (char c : hole_value)
- value_bv.emplace_back(c == '1'? RTLIL::S1 : RTLIL::S0);
- std::reverse(value_bv.begin(), value_bv.end());
+ for (unsigned int i = 0; i < hole_value.size(); ++i) {
+ int bit_idx = GetSize(hole_value) - 1 - i;
+ auto it = hole_loc_idx_to_sigbit.find(std::make_pair(hole_loc, i));
+ log_assert(it != hole_loc_idx_to_sigbit.end());
+
+ RTLIL::SigBit hole_sigbit = it->second;
+ log_assert(hole_sigbit.wire != nullptr);
+ log_assert(hole_value[bit_idx] == '0' || hole_value[bit_idx] == '1');
+ RTLIL::SigSpec lhs(hole_sigbit.wire, hole_sigbit.offset, 1);
+ RTLIL::State hole_bit_val = hole_value[bit_idx] == '1'? RTLIL::State::S1 : RTLIL::State::S0;
+ if (!quiet)
+ log("Specializing %s with %s = %d.\n", module->name.c_str(), log_signal(hole_sigbit), hole_bit_val == RTLIL::State::S0? 0 : 1)
+;
+ module->connect(lhs, hole_bit_val);
+ }
}
}
void allconstify_inputs(RTLIL::Module *module, const pool<std::string> &input_wires) {
for (auto &n : input_wires) {
RTLIL::Wire *input = module->wire(n);
-#ifndef NDEBUG
log_assert(input != nullptr);
-#endif
RTLIL::Cell *allconst = module->addCell("$allconst$" + n, "$allconst");
allconst->setParam(ID(WIDTH), input->width);
@@ -314,7 +172,7 @@ void allconstify_inputs(RTLIL::Module *module, const pool<std::string> &input_wi
module->fixup_ports();
}
-void assume_miter_outputs(RTLIL::Module *module, const QbfSolveOptions &opt) {
+void assume_miter_outputs(RTLIL::Module *module, bool assume_neg) {
std::vector<RTLIL::Wire *> wires_to_assume;
for (auto w : module->wires())
if (w->port_output && w->width == 1)
@@ -329,7 +187,7 @@ void assume_miter_outputs(RTLIL::Module *module, const QbfSolveOptions &opt) {
log("\n");
}
- if (opt.assume_neg) {
+ if (assume_neg) {
for (unsigned int i = 0; i < wires_to_assume.size(); ++i) {
RTLIL::SigSpec n_wire = module->LogicNot(wires_to_assume[i]->name.str() + "__n__qbfsat", wires_to_assume[i], false, wires_to_assume[i]->get_src_attribute());
wires_to_assume[i] = n_wire.as_wire();
@@ -349,9 +207,7 @@ void assume_miter_outputs(RTLIL::Module *module, const QbfSolveOptions &opt) {
wires_to_assume.swap(buf);
}
-#ifndef NDEBUG
log_assert(wires_to_assume.size() == 1);
-#endif
module->addAssume("$assume_qbfsat_miter_outputs", wires_to_assume[0], RTLIL::S1);
}
@@ -359,10 +215,17 @@ QbfSolutionType call_qbf_solver(RTLIL::Module *mod, const QbfSolveOptions &opt,
//Execute and capture stdout from `yosys-smtbmc -s z3 -t 1 -g --binary [--dump-smt2 <file>]`
QbfSolutionType ret;
const std::string yosys_smtbmc_exe = proc_self_dirname() + "yosys-smtbmc";
- const std::string smt2_command = "write_smt2 -stbv -wires " + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2";
const std::string smtbmc_warning = "z3: WARNING:";
- const std::string smtbmc_cmd = yosys_smtbmc_exe + " -s " + (get_solver_name(opt)) + (opt.timeout != 0? stringf(" --timeout %d", opt.timeout) : "") + " -t 1 -g --binary " + (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file + " " : "") + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2 2>&1";
-
+ const std::string smtbmc_cmd = stringf("%s -s %s %s -t 1 -g --binary %s %s/problem%d.smt2 2>&1",
+ yosys_smtbmc_exe.c_str(), opt.get_solver_name().c_str(),
+ (opt.timeout != 0? stringf("--timeout %d", opt.timeout) : "").c_str(),
+ (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file : "").c_str(),
+ tempdir_name.c_str(), iter_num);
+
+ std::string smt2_command = "write_smt2 -stbv -wires ";
+ for (auto &solver_opt : opt.solver_options)
+ smt2_command += stringf("-solver-option %s %s ", solver_opt.first.c_str(), solver_opt.second.c_str());
+ smt2_command += stringf("%s/problem%d.smt2", tempdir_name.c_str(), iter_num);
Pass::call(mod->design, smt2_command);
auto process_line = [&ret, &smtbmc_warning, &opt, &quiet](const std::string &line) {
@@ -376,45 +239,59 @@ QbfSolutionType call_qbf_solver(RTLIL::Module *mod, const QbfSolveOptions &opt,
};
log_header(mod->design, "Solving QBF-SAT problem.\n");
if (!quiet) log("Launching \"%s\".\n", smtbmc_cmd.c_str());
+ int64_t begin = PerformanceTimer::query();
run_command(smtbmc_cmd, process_line);
+ int64_t end = PerformanceTimer::query();
+ ret.solver_time = (end - begin) / 1e9f;
+ if (!quiet) log("Solver finished in %.3f seconds.\n", ret.solver_time);
- recover_solution(ret);
+ ret.recover_solution();
return ret;
}
QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) {
QbfSolutionType ret, best_soln;
- const std::string tempdir_name = make_temp_dir("/tmp/yosys-z3-XXXXXX");
+ const std::string tempdir_name = make_temp_dir("/tmp/yosys-qbfsat-XXXXXX");
RTLIL::Module *module = mod;
RTLIL::Design *design = module->design;
std::string module_name = module->name.str();
- RTLIL::Wire *wire_to_optimize = nullptr;
- RTLIL::IdString wire_to_optimize_name;
+ RTLIL::IdString wire_to_optimize_name = "";
bool maximize = false;
log_assert(module->design != nullptr);
Pass::call(design, "design -push-copy");
//Replace input wires with wires assigned $allconst cells:
- pool<std::string> input_wires = validate_design_and_get_inputs(module, opt);
+ pool<std::string> input_wires = validate_design_and_get_inputs(module, opt.assume_outputs);
allconstify_inputs(module, input_wires);
if (opt.assume_outputs)
- assume_miter_outputs(module, opt);
+ assume_miter_outputs(module, opt.assume_neg);
//Find the wire to be optimized, if any:
- for (auto wire : module->wires())
- if (wire->get_bool_attribute("\\maximize") || wire->get_bool_attribute("\\minimize"))
- wire_to_optimize = wire;
- if (wire_to_optimize != nullptr) {
- wire_to_optimize_name = wire_to_optimize->name;
- maximize = wire_to_optimize->get_bool_attribute("\\maximize");
+ for (auto wire : module->wires()) {
+ if (wire->get_bool_attribute("\\maximize") || wire->get_bool_attribute("\\minimize")) {
+ wire_to_optimize_name = wire->name;
+ maximize = wire->get_bool_attribute("\\maximize");
+ if (opt.nooptimize) {
+ if (maximize)
+ wire->set_bool_attribute("\\maximize", false);
+ else
+ wire->set_bool_attribute("\\minimize", false);
+ }
+ }
}
- if (opt.nobisection || opt.nooptimize) {
- if (wire_to_optimize != nullptr && opt.nooptimize) {
- wire_to_optimize->set_bool_attribute("\\maximize", false);
- wire_to_optimize->set_bool_attribute("\\minimize", false);
- }
+ //If -O1 or -O2 was specified, use ABC to simplify the problem:
+ if (opt.oflag == opt.OptimizationLevel::O1)
+ Pass::call(module->design, "abc -g AND,NAND,OR,NOR,XOR,XNOR,MUX,NMUX -script +print_stats;strash;print_stats;drwsat;print_stats;fraig;print_stats;refactor,-N,10,-lz;print_stats;&get,-n;&dch,-pem;&nf;&put " + mod->name.str());
+ else if (opt.oflag == opt.OptimizationLevel::O2)
+ Pass::call(module->design, "abc -g AND,NAND,OR,NOR,XOR,XNOR,MUX,NMUX -script +print_stats;strash;print_stats;drwsat;print_stats;dch,-S,1000000,-C,100000,-p;print_stats;fraig;print_stats;refactor,-N,15,-lz;print_stats;dc2,-pbl;print_stats;drwsat;print_stats;&get,-n;&dch,-pem;&nf;&put " + mod->name.str());
+ if (opt.oflag != opt.OptimizationLevel::O0) {
+ Pass::call(module->design, "techmap");
+ Pass::call(module->design, "opt");
+ }
+
+ if (opt.nobisection || opt.nooptimize || wire_to_optimize_name == "") {
ret = call_qbf_solver(module, opt, tempdir_name, false, 0);
} else {
//Do the iterated bisection method:
@@ -423,11 +300,12 @@ QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) {
unsigned int failure = 0;
unsigned int cur_thresh = 0;
- log_assert(wire_to_optimize != nullptr);
- log("%s wire \"%s\".\n", (maximize? "Maximizing" : "Minimizing"), log_signal(wire_to_optimize));
+ log_assert(wire_to_optimize_name != "");
+ log_assert(module->wire(wire_to_optimize_name) != nullptr);
+ log("%s wire \"%s\".\n", (maximize? "Maximizing" : "Minimizing"), wire_to_optimize_name.c_str());
//If maximizing, grow until we get a failure. Then bisect success and failure.
- while (failure == 0 || success - failure > 1) {
+ while (failure == 0 || difference(success, failure) > 1) {
Pass::call(design, "design -push-copy");
log_header(design, "Preparing QBF-SAT problem.\n");
@@ -465,8 +343,9 @@ QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) {
//sometimes this happens if we get an 'unknown' or timeout
if (!maximize && success < failure)
break;
- else if (maximize && success > failure)
+ else if (maximize && failure != 0 && success > failure)
break;
+
} else {
//Treat 'unknown' as UNSAT
failure = cur_thresh;
@@ -479,8 +358,12 @@ QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) {
}
iter_num++;
- cur_thresh = (maximize && failure == 0)? 2 * success //growth
- : (success + failure) / 2; //bisection
+ if (maximize && failure == 0 && success == 0)
+ cur_thresh = 2;
+ else if (maximize && failure == 0)
+ cur_thresh = 2 * success; //growth
+ else //if (!maximize || failure != 0)
+ cur_thresh = (success + failure) / 2; //bisection
}
if (success != 0 || failure != 0) {
log("Wire %s is %s at %d.\n", wire_to_optimize_name.c_str(), (maximize? "maximized" : "minimized"), success);
@@ -539,6 +422,13 @@ QbfSolveOptions parse_args(const std::vector<std::string> &args) {
}
continue;
}
+ else if (args[opt.argidx] == "-solver-option") {
+ if (args.size() <= opt.argidx + 2)
+ log_cmd_error("solver option name and value not fully specified.\n");
+ opt.solver_options.emplace(args[opt.argidx+1], args[opt.argidx+2]);
+ opt.argidx += 2;
+ continue;
+ }
else if (args[opt.argidx] == "-timeout") {
if (args.size() <= opt.argidx + 1)
log_cmd_error("timeout not specified.\n");
@@ -552,6 +442,22 @@ QbfSolveOptions parse_args(const std::vector<std::string> &args) {
}
continue;
}
+ else if (args[opt.argidx].substr(0, 2) == "-O" && args[opt.argidx].size() == 3) {
+ switch (args[opt.argidx][2]) {
+ case '0':
+ opt.oflag = opt.OptimizationLevel::O0;
+ break;
+ case '1':
+ opt.oflag = opt.OptimizationLevel::O1;
+ break;
+ case '2':
+ opt.oflag = opt.OptimizationLevel::O2;
+ break;
+ default:
+ log_cmd_error("unknown argument %s\n", args[opt.argidx].c_str());
+ }
+ continue;
+ }
else if (args[opt.argidx] == "-sat") {
opt.sat = true;
continue;
@@ -594,36 +500,9 @@ QbfSolveOptions parse_args(const std::vector<std::string> &args) {
return opt;
}
-void print_proof_failed()
-{
- log("\n");
- log(" ______ ___ ___ _ _ _ _ \n");
- log(" (_____ \\ / __) / __) (_) | | | |\n");
- log(" _____) )___ ___ ___ _| |__ _| |__ _____ _| | _____ __| | |\n");
- log(" | ____/ ___) _ \\ / _ (_ __) (_ __|____ | | || ___ |/ _ |_|\n");
- log(" | | | | | |_| | |_| || | | | / ___ | | || ____( (_| |_ \n");
- log(" |_| |_| \\___/ \\___/ |_| |_| \\_____|_|\\_)_____)\\____|_|\n");
- log("\n");
-}
-
-void print_qed()
-{
- log("\n");
- log(" /$$$$$$ /$$$$$$$$ /$$$$$$$ \n");
- log(" /$$__ $$ | $$_____/ | $$__ $$ \n");
- log(" | $$ \\ $$ | $$ | $$ \\ $$ \n");
- log(" | $$ | $$ | $$$$$ | $$ | $$ \n");
- log(" | $$ | $$ | $$__/ | $$ | $$ \n");
- log(" | $$/$$ $$ | $$ | $$ | $$ \n");
- log(" | $$$$$$/ /$$| $$$$$$$$ /$$| $$$$$$$//$$\n");
- log(" \\____ $$$|__/|________/|__/|_______/|__/\n");
- log(" \\__/ \n");
- log("\n");
-}
-
struct QbfSatPass : public Pass {
QbfSatPass() : Pass("qbfsat", "solve a 2QBF-SAT problem in the circuit") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -662,9 +541,17 @@ struct QbfSatPass : public Pass {
log("\n");
log(" -solver <solver>\n");
log(" Use a particular solver. Choose one of: \"z3\", \"yices\", and \"cvc4\".\n");
+ log(" (default: yices)\n");
+ log("\n");
+ log(" -solver-option <name> <value>\n");
+ log(" Set the specified solver option in the SMT-LIBv2 problem file.\n");
log("\n");
log(" -timeout <value>\n");
log(" Set the per-iteration timeout in seconds.\n");
+ log(" (default: no timeout)\n");
+ log("\n");
+ log(" -O0, -O1, -O2\n");
+ log(" Control the use of ABC to simplify the QBF-SAT problem before solving.\n");
log("\n");
log(" -sat\n");
log(" Generate an error if the solver does not return \"sat\".\n");
@@ -690,7 +577,7 @@ struct QbfSatPass : public Pass {
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing QBFSAT pass (solving QBF-SAT problems in the circuit).\n");
QbfSolveOptions opt = parse_args(args);
@@ -719,12 +606,12 @@ struct QbfSatPass : public Pass {
else if (ret.sat) {
print_qed();
if (opt.write_solution) {
- write_solution(module, ret, opt.write_soln_soln_file);
+ ret.write_solution(module, opt.write_soln_soln_file);
}
if (opt.specialize) {
specialize(module, ret);
} else {
- dump_model(module, ret);
+ ret.dump_model(module);
}
if (opt.unsat)
log_cmd_error("expected problem to be UNSAT\n");
diff --git a/passes/sat/qbfsat.h b/passes/sat/qbfsat.h
new file mode 100644
index 000000000..c96c6f818
--- /dev/null
+++ b/passes/sat/qbfsat.h
@@ -0,0 +1,253 @@
+/* -*- c++ -*-
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2020 Alberto Gonzalez <boqwxp@airmail.cc>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef QBFSAT_H
+#define QBFSAT_H
+
+#include "kernel/yosys.h"
+#include <numeric>
+
+YOSYS_NAMESPACE_BEGIN
+
+struct QbfSolveOptions {
+ bool specialize = false, specialize_from_file = false, write_solution = false, nocleanup = false;
+ bool dump_final_smt2 = false, assume_outputs = false, assume_neg = false, nooptimize = false;
+ bool nobisection = false, sat = false, unsat = false, show_smtbmc = false;
+ enum Solver{Z3, Yices, CVC4} solver = Yices;
+ enum OptimizationLevel{O0, O1, O2} oflag = O0;
+ dict<std::string, std::string> solver_options;
+ int timeout = 0;
+ std::string specialize_soln_file = "";
+ std::string write_soln_soln_file = "";
+ std::string dump_final_smt2_file = "";
+ size_t argidx = 0;
+
+ std::string get_solver_name() const {
+ if (solver == Solver::Z3)
+ return "z3";
+ else if (solver == Solver::Yices)
+ return "yices";
+ else if (solver == Solver::CVC4)
+ return "cvc4";
+
+ log_cmd_error("unknown solver specified.\n");
+ return "";
+ }
+};
+
+struct QbfSolutionType {
+ std::vector<std::string> stdout_lines = {};
+ dict<pool<std::string>, std::string> hole_to_value = {};
+ double solver_time = 0;
+ bool sat = false;
+ bool unknown = true; //true if neither 'sat' nor 'unsat'
+
+ dict<std::pair<pool<std::string>, int>, RTLIL::SigBit> get_hole_loc_idx_sigbit_map(RTLIL::Module *module) const {
+ dict<std::pair<pool<std::string>, int>, RTLIL::SigBit> hole_loc_idx_to_sigbit;
+ pool<RTLIL::SigBit> anyconst_sigbits;
+ dict<RTLIL::SigBit, RTLIL::SigBit> anyconst_sigbit_to_wire_sigbit;
+
+ for (auto cell : module->cells()) {
+ pool<std::string> cell_src = cell->get_strpool_attribute(ID::src);
+ auto pos = hole_to_value.find(cell_src);
+ if (pos != hole_to_value.end() && cell->type.in("$anyconst", "$anyseq")) {
+ RTLIL::SigSpec port_y = cell->getPort(ID::Y);
+ for (int i = GetSize(port_y) - 1; i >= 0; --i) {
+ hole_loc_idx_to_sigbit[std::make_pair(pos->first, i)] = port_y[i];
+ anyconst_sigbits.insert(port_y[i]);
+ }
+ }
+ }
+
+ for (auto &conn : module->connections()) {
+ auto lhs = conn.first;
+ auto rhs = conn.second;
+ for (auto i = 0; i < GetSize(rhs); ++i) {
+ if (anyconst_sigbits[rhs[i]]) {
+ auto pos = anyconst_sigbit_to_wire_sigbit.find(rhs[i]);
+ if (pos != anyconst_sigbit_to_wire_sigbit.end())
+ log_cmd_error("conflicting names for hole $anyconst sigbit %s\n", log_signal(rhs[i]));
+ anyconst_sigbit_to_wire_sigbit[rhs[i]] = lhs[i];
+ }
+ }
+ }
+
+ for (auto &it : hole_loc_idx_to_sigbit) {
+ auto pos = anyconst_sigbit_to_wire_sigbit.find(it.second);
+ if (pos != anyconst_sigbit_to_wire_sigbit.end())
+ it.second = pos->second;
+ }
+
+ return hole_loc_idx_to_sigbit;
+ }
+
+ void dump_model(RTLIL::Module *module) const {
+ log("Satisfiable model:\n");
+ auto hole_loc_idx_to_sigbit = get_hole_loc_idx_sigbit_map(module);
+ for (auto &it : hole_to_value) {
+ pool<std::string> hole_loc = it.first;
+ std::string hole_value = it.second;
+
+ for (unsigned int i = 0; i < hole_value.size(); ++i) {
+ int bit_idx = GetSize(hole_value) - 1 - i;
+ auto it = hole_loc_idx_to_sigbit.find(std::make_pair(hole_loc, i));
+ log_assert(it != hole_loc_idx_to_sigbit.end());
+
+ RTLIL::SigBit hole_sigbit = it->second;
+ log("\t%s = 1'b%c\n", log_signal(hole_sigbit), hole_value[bit_idx]);
+ }
+ }
+ }
+
+ void write_solution(RTLIL::Module *module, const std::string &file) const {
+ std::ofstream fout(file.c_str());
+ if (!fout)
+ log_cmd_error("could not open solution file for writing.\n");
+
+ //There is a question here: How exactly shall we identify holes?
+ //There are at least two reasonable options:
+ //1. By the source location of the $anyconst cells
+ //2. By the name(s) of the wire(s) connected to each SigBit of the $anyconst cell->getPort(ID::Y) SigSpec.
+ //
+ //Option 1 has the benefit of being very precise. There is very limited potential for confusion, as long
+ //as the source attribute has been set. However, if the source attribute is not set, this won't work.
+ //More importantly, we want to have the ability to port hole assignments to other modules with compatible
+ //hole names and widths. Obviously in those cases source locations of the $anyconst cells will not match.
+ //
+ //Option 2 has the benefits previously described, but wire names can be changed automatically by
+ //optimization or techmapping passes, especially when (ex/im)porting from BLIF for optimization with ABC.
+ //
+ //The approach taken here is to allow both options. We write the assignment information for each bit of
+ //the solution on a separate line. Each line is of one of two forms:
+ //
+ //location bit name = value
+ //location bit name [offset] = value
+ //
+ //where '[', ']', and '=' are literal symbols, "location" is the $anyconst cell source location attribute,
+ //"bit" is the index of the $anyconst cell, "name" is the `wire->name` field of the SigBit corresponding
+ //to the current bit of the $anyconst cell->getPort(ID::Y), "offset" is the `offset` field of that same
+ //SigBit, and "value", which is either '0' or '1', represents the assignment for that bit.
+ auto hole_loc_idx_to_sigbit = get_hole_loc_idx_sigbit_map(module);
+ for (auto &x : hole_to_value) {
+ std::string src_as_str = std::accumulate(x.first.begin(), x.first.end(), std::string(), [](const std::string &a, const std::string &b){return a + "|" + b;});
+ for (auto i = 0; i < GetSize(x.second); ++i)
+ fout << src_as_str.c_str() << " " << i << " " << log_signal(hole_loc_idx_to_sigbit[std::make_pair(x.first, i)]) << " = " << x.second[GetSize(x.second) - 1 - i] << std::endl;
+ }
+ }
+
+ void recover_solution() {
+ YS_REGEX_TYPE sat_regex = YS_REGEX_COMPILE("Status: PASSED");
+ YS_REGEX_TYPE unsat_regex = YS_REGEX_COMPILE("Solver Error.*model is not available");
+ YS_REGEX_TYPE unsat_regex2 = YS_REGEX_COMPILE("Status: FAILED");
+ YS_REGEX_TYPE timeout_regex = YS_REGEX_COMPILE("No solution found! \\(timeout\\)");
+ YS_REGEX_TYPE timeout_regex2 = YS_REGEX_COMPILE("No solution found! \\(interrupted\\)");
+ YS_REGEX_TYPE unknown_regex = YS_REGEX_COMPILE("No solution found! \\(unknown\\)");
+ YS_REGEX_TYPE unknown_regex2 = YS_REGEX_COMPILE("Unexpected EOF response from solver");
+ YS_REGEX_TYPE memout_regex = YS_REGEX_COMPILE("Solver Error:.*error \"out of memory\"");
+ YS_REGEX_TYPE hole_value_regex = YS_REGEX_COMPILE_WITH_SUBS("Value for anyconst in [a-zA-Z0-9_]* \\(([^:]*:[^\\)]*)\\): (.*)");
+#ifndef NDEBUG
+ YS_REGEX_TYPE hole_loc_regex = YS_REGEX_COMPILE("[^:]*:[0-9]+.[0-9]+-[0-9]+.[0-9]+");
+ YS_REGEX_TYPE hole_val_regex = YS_REGEX_COMPILE("[0-9]+");
+#endif
+ YS_REGEX_MATCH_TYPE m;
+ bool sat_regex_found = false;
+ bool unsat_regex_found = false;
+ dict<std::string, bool> hole_value_recovered;
+ for (const std::string &x : stdout_lines) {
+ if(YS_REGEX_NS::regex_search(x, m, hole_value_regex)) {
+ std::string loc = m[1].str();
+ std::string val = m[2].str();
+#ifndef NDEBUG
+ log_assert(YS_REGEX_NS::regex_search(loc, hole_loc_regex));
+ log_assert(YS_REGEX_NS::regex_search(val, hole_val_regex));
+#endif
+ auto locs = split_tokens(loc, "|");
+ pool<std::string> loc_pool(locs.begin(), locs.end());
+ hole_to_value[loc_pool] = val;
+ }
+ else if (YS_REGEX_NS::regex_search(x, sat_regex)) {
+ sat_regex_found = true;
+ sat = true;
+ unknown = false;
+ }
+ else if (YS_REGEX_NS::regex_search(x, unsat_regex)) {
+ unsat_regex_found = true;
+ sat = false;
+ unknown = false;
+ }
+ else if (YS_REGEX_NS::regex_search(x, memout_regex)) {
+ unknown = true;
+ log_warning("solver ran out of memory\n");
+ }
+ else if (YS_REGEX_NS::regex_search(x, timeout_regex)) {
+ unknown = true;
+ log_warning("solver timed out\n");
+ }
+ else if (YS_REGEX_NS::regex_search(x, timeout_regex2)) {
+ unknown = true;
+ log_warning("solver timed out\n");
+ }
+ else if (YS_REGEX_NS::regex_search(x, unknown_regex)) {
+ unknown = true;
+ log_warning("solver returned \"unknown\"\n");
+ }
+ else if (YS_REGEX_NS::regex_search(x, unsat_regex2)) {
+ unsat_regex_found = true;
+ sat = false;
+ unknown = false;
+ }
+ else if (YS_REGEX_NS::regex_search(x, unknown_regex2)) {
+ unknown = true;
+ }
+ }
+ log_assert(!unknown && sat? sat_regex_found : true);
+ log_assert(!unknown && !sat? unsat_regex_found : true);
+ }
+};
+
+void print_proof_failed()
+{
+ log("\n");
+ log(" ______ ___ ___ _ _ _ _ \n");
+ log(" (_____ \\ / __) / __) (_) | | | |\n");
+ log(" _____) )___ ___ ___ _| |__ _| |__ _____ _| | _____ __| | |\n");
+ log(" | ____/ ___) _ \\ / _ (_ __) (_ __|____ | | || ___ |/ _ |_|\n");
+ log(" | | | | | |_| | |_| || | | | / ___ | | || ____( (_| |_ \n");
+ log(" |_| |_| \\___/ \\___/ |_| |_| \\_____|_|\\_)_____)\\____|_|\n");
+ log("\n");
+}
+
+void print_qed()
+{
+ log("\n");
+ log(" /$$$$$$ /$$$$$$$$ /$$$$$$$ \n");
+ log(" /$$__ $$ | $$_____/ | $$__ $$ \n");
+ log(" | $$ \\ $$ | $$ | $$ \\ $$ \n");
+ log(" | $$ | $$ | $$$$$ | $$ | $$ \n");
+ log(" | $$ | $$ | $$__/ | $$ | $$ \n");
+ log(" | $$/$$ $$ | $$ | $$ | $$ \n");
+ log(" | $$$$$$/ /$$| $$$$$$$$ /$$| $$$$$$$//$$\n");
+ log(" \\____ $$$|__/|________/|__/|_______/|__/\n");
+ log(" \\__/ \n");
+ log("\n");
+}
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc
index 6acdbc800..9fdac6147 100644
--- a/passes/sat/sat.cc
+++ b/passes/sat/sat.cc
@@ -256,13 +256,13 @@ struct SatHelper
{
RTLIL::SigSpec big_lhs, big_rhs;
- for (auto &it : module->wires_)
+ for (auto wire : module->wires())
{
- if (it.second->attributes.count(ID::init) == 0)
+ if (wire->attributes.count(ID::init) == 0)
continue;
- RTLIL::SigSpec lhs = sigmap(it.second);
- RTLIL::SigSpec rhs = it.second->attributes.at(ID::init);
+ RTLIL::SigSpec lhs = sigmap(wire);
+ RTLIL::SigSpec rhs = wire->attributes.at(ID::init);
log_assert(lhs.size() == rhs.size());
RTLIL::SigSpec removed_bits;
@@ -893,7 +893,7 @@ void print_qed()
struct SatPass : public Pass {
SatPass() : Pass("sat", "solve a SAT problem in the circuit") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1060,7 +1060,7 @@ struct SatPass : public Pass {
log(" Like -falsify but do not return an error for timeouts.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::vector<std::pair<std::string, std::string>> sets, sets_init, prove, prove_x;
std::map<int, std::vector<std::pair<std::string, std::string>>> sets_at;
@@ -1365,7 +1365,7 @@ struct SatPass : public Pass {
if (show_public) {
for (auto wire : module->wires())
- if (wire->name[0] == '\\')
+ if (wire->name.isPublic())
shows.push_back(wire->name.str());
}
diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc
index 03ca42cf3..3ba66bd33 100644
--- a/passes/sat/sim.cc
+++ b/passes/sat/sim.cc
@@ -20,6 +20,9 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
+#include "kernel/mem.h"
+
+#include <ctime>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -62,6 +65,7 @@ struct SimInstance
pool<SigBit> dirty_bits;
pool<Cell*> dirty_cells;
+ pool<IdString> dirty_memories;
pool<SimInstance*, hash_ptr_ops> dirty_children;
struct ff_state_t
@@ -72,16 +76,20 @@ struct SimInstance
struct mem_state_t
{
- Const past_wr_clk;
- Const past_wr_en;
- Const past_wr_addr;
- Const past_wr_data;
+ Mem *mem;
+ std::vector<Const> past_wr_clk;
+ std::vector<Const> past_wr_en;
+ std::vector<Const> past_wr_addr;
+ std::vector<Const> past_wr_data;
Const data;
};
dict<Cell*, ff_state_t> ff_database;
- dict<Cell*, mem_state_t> mem_database;
+ dict<IdString, mem_state_t> mem_database;
pool<Cell*> formal_database;
+ dict<Cell*, IdString> mem_cells;
+
+ std::vector<Mem> memories;
dict<Wire*, pair<int, Const>> vcd_database;
@@ -118,6 +126,19 @@ struct SimInstance
}
}
+ memories = Mem::get_all_memories(module);
+ for (auto &mem : memories) {
+ auto &mdb = mem_database[mem.memid];
+ mdb.mem = &mem;
+ for (auto &port : mem.wr_ports) {
+ mdb.past_wr_clk.push_back(Const(State::Sx));
+ mdb.past_wr_en.push_back(Const(State::Sx, GetSize(port.en)));
+ mdb.past_wr_addr.push_back(Const(State::Sx, GetSize(port.addr)));
+ mdb.past_wr_data.push_back(Const(State::Sx, GetSize(port.data)));
+ }
+ mdb.data = mem.get_init_data();
+ }
+
for (auto cell : module->cells())
{
Module *mod = module->design->module(cell->type);
@@ -143,27 +164,10 @@ struct SimInstance
ff_database[cell] = ff;
}
- if (cell->type == ID($mem))
+ if (cell->type.in(ID($mem), ID($meminit), ID($memwr), ID($memrd)))
{
- mem_state_t mem;
-
- mem.past_wr_clk = Const(State::Sx, GetSize(cell->getPort(ID::WR_CLK)));
- mem.past_wr_en = Const(State::Sx, GetSize(cell->getPort(ID::WR_EN)));
- mem.past_wr_addr = Const(State::Sx, GetSize(cell->getPort(ID::WR_ADDR)));
- mem.past_wr_data = Const(State::Sx, GetSize(cell->getPort(ID::WR_DATA)));
-
- mem.data = cell->getParam(ID::INIT);
- int sz = cell->getParam(ID::SIZE).as_int() * cell->getParam(ID::WIDTH).as_int();
-
- if (GetSize(mem.data) > sz)
- mem.data.bits.resize(sz);
-
- while (GetSize(mem.data) < sz)
- mem.data.bits.push_back(State::Sx);
-
- mem_database[cell] = mem;
+ mem_cells[cell] = cell->parameters.at(ID::MEMID).decode_string();
}
-
if (cell->type.in(ID($assert), ID($cover), ID($assume))) {
formal_database.insert(cell);
}
@@ -185,7 +189,8 @@ struct SimInstance
for (auto &it : mem_database) {
mem_state_t &mem = it.second;
- zinit(mem.past_wr_en);
+ for (auto &val : mem.past_wr_en)
+ zinit(val);
zinit(mem.data);
}
}
@@ -256,37 +261,9 @@ struct SimInstance
if (formal_database.count(cell))
return;
- if (mem_database.count(cell))
+ if (mem_cells.count(cell))
{
- mem_state_t &mem = mem_database.at(cell);
-
- int num_rd_ports = cell->getParam(ID::RD_PORTS).as_int();
-
- int size = cell->getParam(ID::SIZE).as_int();
- int offset = cell->getParam(ID::OFFSET).as_int();
- int abits = cell->getParam(ID::ABITS).as_int();
- int width = cell->getParam(ID::WIDTH).as_int();
-
- if (cell->getParam(ID::RD_CLK_ENABLE).as_bool())
- log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module), log_id(cell));
-
- SigSpec rd_addr_sig = cell->getPort(ID::RD_ADDR);
- SigSpec rd_data_sig = cell->getPort(ID::RD_DATA);
-
- for (int port_idx = 0; port_idx < num_rd_ports; port_idx++)
- {
- Const addr = get_state(rd_addr_sig.extract(port_idx*abits, abits));
- Const data = Const(State::Sx, width);
-
- if (addr.is_fully_def()) {
- int index = addr.as_int() - offset;
- if (index >= 0 && index < size)
- data = mem.data.extract(index*width, width);
- }
-
- set_state(rd_data_sig.extract(port_idx*width, width), data);
- }
-
+ dirty_memories.insert(mem_cells[cell]);
return;
}
@@ -349,6 +326,29 @@ struct SimInstance
log_error("Unsupported cell type: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
}
+ void update_memory(IdString id) {
+ auto &mdb = mem_database[id];
+ auto &mem = *mdb.mem;
+
+ for (int port_idx = 0; port_idx < GetSize(mem.rd_ports); port_idx++)
+ {
+ auto &port = mem.rd_ports[port_idx];
+ Const addr = get_state(port.addr);
+ Const data = Const(State::Sx, mem.width);
+
+ if (port.clk_enable)
+ log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module), log_id(mem.memid));
+
+ if (addr.is_fully_def()) {
+ int index = addr.as_int() - mem.start_offset;
+ if (index >= 0 && index < mem.size)
+ data = mdb.data.extract(index*mem.width, mem.width);
+ }
+
+ set_state(port.data, data);
+ }
+ }
+
void update_ph1()
{
pool<Cell*> queue_cells;
@@ -380,6 +380,10 @@ struct SimInstance
continue;
}
+ for (auto &memid : dirty_memories)
+ update_memory(memid);
+ dirty_memories.clear();
+
for (auto wire : queue_outports)
if (instance->hasPort(wire->name)) {
Const value = get_state(wire);
@@ -423,50 +427,40 @@ struct SimInstance
for (auto &it : mem_database)
{
- Cell *cell = it.first;
- mem_state_t &mem = it.second;
-
- int num_wr_ports = cell->getParam(ID::WR_PORTS).as_int();
+ mem_state_t &mdb = it.second;
+ auto &mem = *mdb.mem;
- int size = cell->getParam(ID::SIZE).as_int();
- int offset = cell->getParam(ID::OFFSET).as_int();
- int abits = cell->getParam(ID::ABITS).as_int();
- int width = cell->getParam(ID::WIDTH).as_int();
-
- Const wr_clk_enable = cell->getParam(ID::WR_CLK_ENABLE);
- Const wr_clk_polarity = cell->getParam(ID::WR_CLK_POLARITY);
- Const current_wr_clk = get_state(cell->getPort(ID::WR_CLK));
-
- for (int port_idx = 0; port_idx < num_wr_ports; port_idx++)
+ for (int port_idx = 0; port_idx < GetSize(mem.wr_ports); port_idx++)
{
+ auto &port = mem.wr_ports[port_idx];
Const addr, data, enable;
- if (wr_clk_enable[port_idx] == State::S0)
+ if (!port.clk_enable)
{
- addr = get_state(cell->getPort(ID::WR_ADDR).extract(port_idx*abits, abits));
- data = get_state(cell->getPort(ID::WR_DATA).extract(port_idx*width, width));
- enable = get_state(cell->getPort(ID::WR_EN).extract(port_idx*width, width));
+ addr = get_state(port.addr);
+ data = get_state(port.data);
+ enable = get_state(port.en);
}
else
{
- if (wr_clk_polarity[port_idx] == State::S1 ?
- (mem.past_wr_clk[port_idx] == State::S1 || current_wr_clk[port_idx] != State::S1) :
- (mem.past_wr_clk[port_idx] == State::S0 || current_wr_clk[port_idx] != State::S0))
+ if (port.clk_polarity ?
+ (mdb.past_wr_clk[port_idx] == State::S1 || get_state(port.clk) != State::S1) :
+ (mdb.past_wr_clk[port_idx] == State::S0 || get_state(port.clk) != State::S0))
continue;
- addr = mem.past_wr_addr.extract(port_idx*abits, abits);
- data = mem.past_wr_data.extract(port_idx*width, width);
- enable = mem.past_wr_en.extract(port_idx*width, width);
+ addr = mdb.past_wr_addr[port_idx];
+ data = mdb.past_wr_data[port_idx];
+ enable = mdb.past_wr_en[port_idx];
}
if (addr.is_fully_def())
{
- int index = addr.as_int() - offset;
- if (index >= 0 && index < size)
- for (int i = 0; i < width; i++)
- if (enable[i] == State::S1 && mem.data.bits.at(index*width+i) != data[i]) {
- mem.data.bits.at(index*width+i) = data[i];
- dirty_cells.insert(cell);
+ int index = addr.as_int() - mem.start_offset;
+ if (index >= 0 && index < mem.size)
+ for (int i = 0; i < mem.width; i++)
+ if (enable[i] == State::S1 && mdb.data.bits.at(index*mem.width+i) != data[i]) {
+ mdb.data.bits.at(index*mem.width+i) = data[i];
+ dirty_memories.insert(mem.memid);
did_something = true;
}
}
@@ -497,13 +491,15 @@ struct SimInstance
for (auto &it : mem_database)
{
- Cell *cell = it.first;
mem_state_t &mem = it.second;
- mem.past_wr_clk = get_state(cell->getPort(ID::WR_CLK));
- mem.past_wr_en = get_state(cell->getPort(ID::WR_EN));
- mem.past_wr_addr = get_state(cell->getPort(ID::WR_ADDR));
- mem.past_wr_data = get_state(cell->getPort(ID::WR_DATA));
+ for (int i = 0; i < GetSize(mem.mem->wr_ports); i++) {
+ auto &port = mem.mem->wr_ports[i];
+ mem.past_wr_clk[i] = get_state(port.clk);
+ mem.past_wr_en[i] = get_state(port.en);
+ mem.past_wr_addr[i] = get_state(port.addr);
+ mem.past_wr_data[i] = get_state(port.data);
+ }
}
for (auto cell : formal_database)
@@ -558,17 +554,13 @@ struct SimInstance
for (auto &it : mem_database)
{
- Cell *cell = it.first;
mem_state_t &mem = it.second;
- Const initval = mem.data;
-
- while (GetSize(initval) >= 2) {
- if (initval[GetSize(initval)-1] != State::Sx) break;
- if (initval[GetSize(initval)-2] != State::Sx) break;
- initval.bits.pop_back();
- }
-
- cell->setParam(ID::INIT, initval);
+ mem.mem->clear_inits();
+ MemInit minit;
+ minit.addr = mem.mem->start_offset;
+ minit.data = mem.data;
+ mem.mem->inits.push_back(minit);
+ mem.mem->emit();
}
for (auto it : children)
@@ -630,6 +622,7 @@ struct SimWorker : SimShared
SimInstance *top = nullptr;
std::ofstream vcdfile;
pool<IdString> clock, clockn, reset, resetn;
+ std::string timescale;
~SimWorker()
{
@@ -641,6 +634,17 @@ struct SimWorker : SimShared
if (!vcdfile.is_open())
return;
+ vcdfile << stringf("$version %s $end\n", yosys_version_str);
+
+ std::time_t t = std::time(nullptr);
+ char mbstr[255];
+ if (std::strftime(mbstr, sizeof(mbstr), "%c", std::localtime(&t))) {
+ vcdfile << stringf("$date ") << mbstr << stringf(" $end\n");
+ }
+
+ if (!timescale.empty())
+ vcdfile << stringf("$timescale %s $end\n", timescale.c_str());
+
int id = 1;
top->write_vcd_header(vcdfile, id);
@@ -751,7 +755,7 @@ struct SimWorker : SimShared
struct SimPass : public Pass {
SimPass() : Pass("sim", "simulate the circuit") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -780,6 +784,9 @@ struct SimPass : public Pass {
log(" -zinit\n");
log(" zero-initialize all uninitialized regs and memories\n");
log("\n");
+ log(" -timescale <string>\n");
+ log(" include the specified timescale declaration in the vcd\n");
+ log("\n");
log(" -n <integer>\n");
log(" number of cycles to simulate (default: 20)\n");
log("\n");
@@ -793,7 +800,7 @@ struct SimPass : public Pass {
log(" enable debug output\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
SimWorker worker;
int numcycles = 20;
@@ -803,7 +810,9 @@ struct SimPass : public Pass {
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-vcd" && argidx+1 < args.size()) {
- worker.vcdfile.open(args[++argidx].c_str());
+ std::string vcd_filename = args[++argidx];
+ rewrite_filename(vcd_filename);
+ worker.vcdfile.open(vcd_filename.c_str());
continue;
}
if (args[argidx] == "-n" && argidx+1 < args.size()) {
@@ -830,6 +839,10 @@ struct SimPass : public Pass {
worker.resetn.insert(RTLIL::escape_id(args[++argidx]));
continue;
}
+ if (args[argidx] == "-timescale" && argidx+1 < args.size()) {
+ worker.timescale = args[++argidx];
+ continue;
+ }
if (args[argidx] == "-a") {
worker.hide_internal = false;
continue;
diff --git a/passes/sat/supercover.cc b/passes/sat/supercover.cc
index ba44f02d8..aacc044fb 100644
--- a/passes/sat/supercover.cc
+++ b/passes/sat/supercover.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct SupercoverPass : public Pass {
SupercoverPass() : Pass("supercover", "add hi/lo cover cells for each wire bit") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -35,7 +35,7 @@ struct SupercoverPass : public Pass {
log("checking for a hi signal level and one checking for lo level.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
// bool flag_noinit = false;
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index a54b4913d..035699603 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -27,7 +27,6 @@ OBJS += passes/techmap/extract_fa.o
OBJS += passes/techmap/extract_counter.o
OBJS += passes/techmap/extract_reduce.o
OBJS += passes/techmap/alumacc.o
-OBJS += passes/techmap/dff2dffe.o
OBJS += passes/techmap/dffinit.o
OBJS += passes/techmap/pmuxtree.o
OBJS += passes/techmap/muxcover.o
@@ -41,7 +40,8 @@ OBJS += passes/techmap/insbuf.o
OBJS += passes/techmap/attrmvcp.o
OBJS += passes/techmap/attrmap.o
OBJS += passes/techmap/zinit.o
-OBJS += passes/techmap/dff2dffs.o
+OBJS += passes/techmap/dfflegalize.o
+OBJS += passes/techmap/dffunmap.o
OBJS += passes/techmap/flowmap.o
OBJS += passes/techmap/extractinv.o
endif
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index fae8b2426..192e39372 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -44,6 +44,7 @@
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
+#include "kernel/ffinit.h"
#include "kernel/cost.h"
#include "kernel/log.h"
#include <stdlib.h>
@@ -111,7 +112,7 @@ SigMap assign_map;
RTLIL::Module *module;
std::vector<gate_t> signal_list;
std::map<RTLIL::SigBit, int> signal_map;
-std::map<RTLIL::SigBit, RTLIL::State> signal_init;
+FfInitVals initvals;
pool<std::string> enabled_gates;
bool recover_init, cmos_cost;
@@ -133,10 +134,7 @@ int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1,
gate.in4 = -1;
gate.is_port = false;
gate.bit = bit;
- if (signal_init.count(bit))
- gate.init = signal_init.at(bit);
- else
- gate.init = State::Sx;
+ gate.init = initvals(bit);
signal_list.push_back(gate);
signal_map[bit] = gate.id;
}
@@ -1276,7 +1274,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
struct AbcPass : public Pass {
AbcPass() : Pass("abc", "use ABC for technology mapping") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1460,7 +1458,7 @@ struct AbcPass : public Pass {
log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing ABC pass (technology mapping using ABC).\n");
log_push();
@@ -1468,15 +1466,11 @@ struct AbcPass : public Pass {
assign_map.clear();
signal_list.clear();
signal_map.clear();
- signal_init.clear();
+ initvals.clear();
pi_map.clear();
po_map.clear();
-#ifdef ABCEXTERNAL
- std::string exe_file = ABCEXTERNAL;
-#else
- std::string exe_file = proc_self_dirname() + proc_program_prefix() + "yosys-abc";
-#endif
+ std::string exe_file = yosys_abc_executable;
std::string script_file, liberty_file, constr_file, clk_str;
std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1";
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
@@ -1491,13 +1485,6 @@ struct AbcPass : public Pass {
enabled_gates.clear();
cmos_cost = false;
-#ifdef _WIN32
-#ifndef ABCEXTERNAL
- if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\" + proc_program_prefix()+ "yosys-abc.exe"))
- exe_file = proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc";
-#endif
-#endif
-
// get arguments from scratchpad first, then override by command arguments
std::string lut_arg, luts_arg, g_arg;
exe_file = design->scratchpad_get_string("abc.exe", exe_file /* inherit default value if not set */);
@@ -1854,24 +1841,7 @@ struct AbcPass : public Pass {
}
assign_map.set(mod);
- signal_init.clear();
-
- for (Wire *wire : mod->wires())
- if (wire->attributes.count(ID::init)) {
- SigSpec initsig = assign_map(wire);
- Const initval = wire->attributes.at(ID::init);
- for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++)
- switch (initval[i]) {
- case State::S0:
- signal_init[initsig[i]] = State::S0;
- break;
- case State::S1:
- signal_init[initsig[i]] = State::S1;
- break;
- default:
- break;
- }
- }
+ initvals.set(&assign_map, mod);
if (!dff_mode || !clk_str.empty()) {
abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
@@ -2028,7 +1998,7 @@ struct AbcPass : public Pass {
assign_map.clear();
signal_list.clear();
signal_map.clear();
- signal_init.clear();
+ initvals.clear();
pi_map.clear();
po_map.clear();
diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc
index 06097a6f7..7d017ac40 100644
--- a/passes/techmap/abc9.cc
+++ b/passes/techmap/abc9.cc
@@ -36,7 +36,7 @@ PRIVATE_NAMESPACE_BEGIN
struct Abc9Pass : public ScriptPass
{
Abc9Pass() : ScriptPass("abc9", "use ABC9 for technology mapping") { }
- void on_register() YS_OVERRIDE
+ void on_register() override
{
RTLIL::constpad["abc9.script.default"] = "+&scorr; &sweep; &dc2; &dch -f; &ps; &if {C} {W} {D} {R} -v; &mfs";
RTLIL::constpad["abc9.script.default.area"] = "+&scorr; &sweep; &dc2; &dch -f; &ps; &if {C} {W} {D} {R} -a -v; &mfs";
@@ -81,7 +81,7 @@ struct Abc9Pass : public ScriptPass
"&st; &if {C} -g -K 6; &synch2; &if {C} {W} {D} {R} -v; &save; &load;"\
"&mfs";
}
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -184,7 +184,7 @@ struct Abc9Pass : public ScriptPass
int maxlut;
std::string box_file;
- void clear_flags() YS_OVERRIDE
+ void clear_flags() override
{
exe_cmd.str("");
exe_cmd << "abc9_exe";
@@ -195,7 +195,7 @@ struct Abc9Pass : public ScriptPass
box_file = "";
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::string run_from, run_to;
clear_flags();
@@ -272,7 +272,7 @@ struct Abc9Pass : public ScriptPass
log_pop();
}
- void script() YS_OVERRIDE
+ void script() override
{
if (check_label("check")) {
if (help_mode)
@@ -294,8 +294,8 @@ struct Abc9Pass : public ScriptPass
run("design -load $abc9_map");
run("proc");
run("wbflip");
- run("techmap");
- run("opt");
+ run("techmap -wb -map %$abc9 -map +/techmap.v A:abc9_flop");
+ run("opt -nodffe -nosdff");
if (dff_mode || help_mode) {
if (!help_mode)
active_design->scratchpad_unset("abc9_ops.prep_dff_submod.did_something");
diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc
index 0bf547921..b916b049d 100644
--- a/passes/techmap/abc9_exe.cc
+++ b/passes/techmap/abc9_exe.cc
@@ -293,7 +293,7 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
struct Abc9ExePass : public Pass {
Abc9ExePass() : Pass("abc9_exe", "use ABC9 for technology mapping") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -375,15 +375,11 @@ struct Abc9ExePass : public Pass {
log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing ABC9_EXE pass (technology mapping using ABC9).\n");
-#ifdef ABCEXTERNAL
- std::string exe_file = ABCEXTERNAL;
-#else
- std::string exe_file = proc_self_dirname() + proc_program_prefix()+ "yosys-abc";
-#endif
+ std::string exe_file = yosys_abc_executable;
std::string script_file, clk_str, box_file, lut_file;
std::string delay_target, lutin_shared = "-S 1", wire_delay;
std::string tempdir_name;
@@ -396,13 +392,6 @@ struct Abc9ExePass : public Pass {
show_tempdir = true;
#endif
-#ifdef _WIN32
-#ifndef ABCEXTERNAL
- if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc.exe"))
- exe_file = proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc";
-#endif
-#endif
-
std::string lut_arg, luts_arg;
exe_file = design->scratchpad_get_string("abc9.exe", exe_file /* inherit default value if not set */);
script_file = design->scratchpad_get_string("abc9.script", script_file);
diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc
index 873c37b9a..98d0207c4 100644
--- a/passes/techmap/abc9_ops.cc
+++ b/passes/techmap/abc9_ops.cc
@@ -741,7 +741,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
if (ys_debug(1))
toposort.analyze_loops = true;
- bool no_loops YS_ATTRIBUTE(unused) = toposort.sort();
+ bool no_loops = toposort.sort();
if (ys_debug(1)) {
unsigned i = 0;
@@ -1453,7 +1453,7 @@ void reintegrate(RTLIL::Module *module, bool dff_mode)
for (auto driver_cell : bit_drivers.at(it.first))
for (auto user_cell : it.second)
toposort.edge(driver_cell, user_cell);
- bool no_loops YS_ATTRIBUTE(unused) = toposort.sort();
+ bool no_loops = toposort.sort();
log_assert(no_loops);
for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) {
@@ -1530,7 +1530,7 @@ clone_lut:
struct Abc9OpsPass : public Pass {
Abc9OpsPass() : Pass("abc9_ops", "helper functions for ABC9") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1614,7 +1614,7 @@ struct Abc9OpsPass : public Pass {
log(" inputs and outputs.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n");
diff --git a/passes/techmap/aigmap.cc b/passes/techmap/aigmap.cc
index 2ecb2f35a..ce151c7f3 100644
--- a/passes/techmap/aigmap.cc
+++ b/passes/techmap/aigmap.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct AigmapPass : public Pass {
AigmapPass() : Pass("aigmap", "map logic to and-inverter-graph circuit") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -43,7 +43,7 @@ struct AigmapPass : public Pass {
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool nand_mode = false, select_mode = false;
diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc
index 1925145d3..b16e9750e 100644
--- a/passes/techmap/alumacc.cc
+++ b/passes/techmap/alumacc.cc
@@ -550,7 +550,7 @@ struct AlumaccWorker
struct AlumaccPass : public Pass {
AlumaccPass() : Pass("alumacc", "extract ALU and MACC cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -560,7 +560,7 @@ struct AlumaccPass : public Pass {
log("and $macc cells.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing ALUMACC pass (create $alu and $macc cells).\n");
diff --git a/passes/techmap/attrmap.cc b/passes/techmap/attrmap.cc
index 5f30817d4..8643543c8 100644
--- a/passes/techmap/attrmap.cc
+++ b/passes/techmap/attrmap.cc
@@ -81,7 +81,7 @@ struct AttrmapAction {
struct AttrmapTocase : AttrmapAction {
string name;
- bool apply(IdString &id, Const&) YS_OVERRIDE {
+ bool apply(IdString &id, Const&) override {
if (match_name(name, id, true))
id = RTLIL::escape_id(name);
return true;
@@ -90,7 +90,7 @@ struct AttrmapTocase : AttrmapAction {
struct AttrmapRename : AttrmapAction {
string old_name, new_name;
- bool apply(IdString &id, Const&) YS_OVERRIDE {
+ bool apply(IdString &id, Const&) override {
if (match_name(old_name, id))
id = RTLIL::escape_id(new_name);
return true;
@@ -101,7 +101,7 @@ struct AttrmapMap : AttrmapAction {
bool imap;
string old_name, new_name;
string old_value, new_value;
- bool apply(IdString &id, Const &val) YS_OVERRIDE {
+ bool apply(IdString &id, Const &val) override {
if (match_name(old_name, id) && match_value(old_value, val, true)) {
id = RTLIL::escape_id(new_name);
val = make_value(new_value);
@@ -113,7 +113,7 @@ struct AttrmapMap : AttrmapAction {
struct AttrmapRemove : AttrmapAction {
bool has_value;
string name, value;
- bool apply(IdString &id, Const &val) YS_OVERRIDE {
+ bool apply(IdString &id, Const &val) override {
return !(match_name(name, id) && (!has_value || match_value(value, val)));
}
};
@@ -221,7 +221,7 @@ bool parse_attrmap_paramap_options(size_t &argidx, std::vector<std::string> &arg
struct AttrmapPass : public Pass {
AttrmapPass() : Pass("attrmap", "renaming attributes") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -241,7 +241,7 @@ struct AttrmapPass : public Pass {
log(" -imap keep=\"false\" keep=0 -remove keep=0\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing ATTRMAP pass (move or copy attributes).\n");
@@ -301,7 +301,7 @@ struct AttrmapPass : public Pass {
struct ParamapPass : public Pass {
ParamapPass() : Pass("paramap", "renaming cell parameters") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -317,7 +317,7 @@ struct ParamapPass : public Pass {
log(" paramap -tocase INIT t:LUT4\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing PARAMAP pass (move or copy cell parameters).\n");
diff --git a/passes/techmap/attrmvcp.cc b/passes/techmap/attrmvcp.cc
index e59aa6518..b3202c587 100644
--- a/passes/techmap/attrmvcp.cc
+++ b/passes/techmap/attrmvcp.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct AttrmvcpPass : public Pass {
AttrmvcpPass() : Pass("attrmvcp", "move or copy attributes from wires to driving cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
log("\n");
log(" attrmvcp [options] [selection]\n");
@@ -53,7 +53,7 @@ struct AttrmvcpPass : public Pass {
log(" multiple times.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing ATTRMVCP pass (move or copy attributes).\n");
diff --git a/passes/techmap/clkbufmap.cc b/passes/techmap/clkbufmap.cc
index 3f4b6aa66..1cbd12e3d 100644
--- a/passes/techmap/clkbufmap.cc
+++ b/passes/techmap/clkbufmap.cc
@@ -2,7 +2,7 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- * Copyright (C) 2019 Marcin Kościelnicki <mwk@0x04.net>
+ * Copyright (C) 2019 Marcelina Kościelnicka <mwk@0x04.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -34,33 +34,34 @@ void split_portname_pair(std::string &port1, std::string &port2)
}
struct ClkbufmapPass : public Pass {
- ClkbufmapPass() : Pass("clkbufmap", "insert global buffers on clock networks") { }
- void help() YS_OVERRIDE
+ ClkbufmapPass() : Pass("clkbufmap", "insert clock buffers on clock networks") { }
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" clkbufmap [options] [selection]\n");
log("\n");
- log("Inserts global buffers between nets connected to clock inputs and their drivers.\n");
+ log("Inserts clock buffers between nets connected to clock inputs and their drivers.\n");
log("\n");
log("In the absence of any selection, all wires without the 'clkbuf_inhibit'\n");
- log("attribute will be considered for global buffer insertion.\n");
+ log("attribute will be considered for clock buffer insertion.\n");
log("Alternatively, to consider all wires without the 'buffer_type' attribute set to\n");
log("'none' or 'bufr' one would specify:\n");
log(" 'w:* a:buffer_type=none a:buffer_type=bufr %%u %%d'\n");
log("as the selection.\n");
log("\n");
log(" -buf <celltype> <portname_out>:<portname_in>\n");
- log(" Specifies the cell type to use for the global buffers\n");
+ log(" Specifies the cell type to use for the clock buffers\n");
log(" and its port names. The first port will be connected to\n");
log(" the clock network sinks, and the second will be connected\n");
- log(" to the actual clock source. This option is required.\n");
+ log(" to the actual clock source.\n");
log("\n");
log(" -inpad <celltype> <portname_out>:<portname_in>\n");
log(" If specified, a PAD cell of the given type is inserted on\n");
log(" clock nets that are also top module's inputs (in addition\n");
- log(" to the global buffer).\n");
+ log(" to the clock buffer, if any).\n");
log("\n");
+ log("At least one of -buf or -inpad should be specified.\n");
}
void module_queue(Design *design, Module *module, std::vector<Module *> &modules_sorted, pool<Module *> &modules_processed) {
@@ -76,9 +77,9 @@ struct ClkbufmapPass : public Pass {
modules_processed.insert(module);
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
- log_header(design, "Executing CLKBUFMAP pass (inserting global clock buffers).\n");
+ log_header(design, "Executing CLKBUFMAP pass (inserting clock buffers).\n");
std::string buf_celltype, buf_portname, buf_portname2;
std::string inpad_celltype, inpad_portname, inpad_portname2;
@@ -109,8 +110,8 @@ struct ClkbufmapPass : public Pass {
extra_args(args, argidx, design);
}
- if (buf_celltype.empty())
- log_error("The -buf option is required.\n");
+ if (buf_celltype.empty() && inpad_celltype.empty())
+ log_error("Either the -buf option or -inpad option is required.\n");
// Cell type, port name, bit index.
pool<pair<IdString, pair<IdString, int>>> sink_ports;
@@ -118,6 +119,16 @@ struct ClkbufmapPass : public Pass {
dict<pair<IdString, pair<IdString, int>>, pair<IdString, int>> inv_ports_out;
dict<pair<IdString, pair<IdString, int>>, pair<IdString, int>> inv_ports_in;
+ // If true, use both ther -buf and -inpad cell for input ports that are clocks.
+ bool buffer_inputs = true;
+
+ Module *inpad_mod = design->module(RTLIL::escape_id(inpad_celltype));
+ if (inpad_mod) {
+ Wire *buf_wire = inpad_mod->wire(RTLIL::escape_id(buf_portname));
+ if (buf_wire && buf_wire->get_bool_attribute(ID::clkbuf_driver))
+ buffer_inputs = false;
+ }
+
// Process submodules before module using them.
std::vector<Module *> modules_sorted;
pool<Module *> modules_processed;
@@ -242,19 +253,30 @@ struct ClkbufmapPass : public Pass {
// Clock network not yet buffered, driven by one of
// our cells or a top-level input -- buffer it.
- log("Inserting %s on %s.%s[%d].\n", buf_celltype.c_str(), log_id(module), log_id(wire), i);
- RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(buf_celltype));
- Wire *iwire = module->addWire(NEW_ID);
- cell->setPort(RTLIL::escape_id(buf_portname), mapped_wire_bit);
- cell->setPort(RTLIL::escape_id(buf_portname2), iwire);
- if (wire->port_input && !inpad_celltype.empty() && module->get_bool_attribute(ID::top)) {
+ Wire *iwire = nullptr;
+ RTLIL::Cell *cell = nullptr;
+ bool is_input = wire->port_input && !inpad_celltype.empty() && module->get_bool_attribute(ID::top);
+ if (!buf_celltype.empty() && (!is_input || buffer_inputs)) {
+ log("Inserting %s on %s.%s[%d].\n", buf_celltype.c_str(), log_id(module), log_id(wire), i);
+ cell = module->addCell(NEW_ID, RTLIL::escape_id(buf_celltype));
+ iwire = module->addWire(NEW_ID);
+ cell->setPort(RTLIL::escape_id(buf_portname), mapped_wire_bit);
+ cell->setPort(RTLIL::escape_id(buf_portname2), iwire);
+ }
+ if (is_input) {
log("Inserting %s on %s.%s[%d].\n", inpad_celltype.c_str(), log_id(module), log_id(wire), i);
RTLIL::Cell *cell2 = module->addCell(NEW_ID, RTLIL::escape_id(inpad_celltype));
- cell2->setPort(RTLIL::escape_id(inpad_portname), iwire);
+ if (iwire) {
+ cell2->setPort(RTLIL::escape_id(inpad_portname), iwire);
+ } else {
+ cell2->setPort(RTLIL::escape_id(inpad_portname), mapped_wire_bit);
+ cell = cell2;
+ }
iwire = module->addWire(NEW_ID);
cell2->setPort(RTLIL::escape_id(inpad_portname2), iwire);
}
- buffered_bits[mapped_wire_bit] = make_pair(cell, iwire);
+ if (iwire)
+ buffered_bits[mapped_wire_bit] = make_pair(cell, iwire);
if (wire->port_input) {
input_bits.insert(i);
diff --git a/passes/techmap/deminout.cc b/passes/techmap/deminout.cc
index a7dce9c81..9a23cb90e 100644
--- a/passes/techmap/deminout.cc
+++ b/passes/techmap/deminout.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct DeminoutPass : public Pass {
DeminoutPass() : Pass("deminout", "demote inout ports to input or output") { }
- void help() YS_OVERRIDE
+ void help() override
{
log("\n");
log(" deminout [options] [selection]\n");
@@ -33,7 +33,7 @@ struct DeminoutPass : public Pass {
log("\"Demote\" inout ports to input or output ports, if possible.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing DEMINOUT pass (demote inout ports to input or output).\n");
diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc
deleted file mode 100644
index aa9bbfe17..000000000
--- a/passes/techmap/dff2dffe.cc
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * yosys -- Yosys Open SYnthesis Suite
- *
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-#include "kernel/yosys.h"
-#include "kernel/sigtools.h"
-#include "kernel/celltypes.h"
-#include "passes/techmap/simplemap.h"
-
-USING_YOSYS_NAMESPACE
-PRIVATE_NAMESPACE_BEGIN
-
-struct Dff2dffeWorker
-{
- const dict<IdString, IdString> &direct_dict;
-
- RTLIL::Module *module;
- SigMap sigmap;
- CellTypes ct;
-
- typedef std::pair<RTLIL::Cell*, int> cell_int_t;
- std::map<RTLIL::SigBit, cell_int_t> bit2mux;
- std::vector<RTLIL::Cell*> dff_cells;
- std::map<RTLIL::SigBit, int> bitusers;
-
- typedef std::map<RTLIL::SigBit, bool> pattern_t;
- typedef std::set<pattern_t> patterns_t;
-
-
- Dff2dffeWorker(RTLIL::Module *module, const dict<IdString, IdString> &direct_dict) :
- direct_dict(direct_dict), module(module), sigmap(module), ct(module->design)
- {
- for (auto wire : module->wires()) {
- if (wire->port_output)
- for (auto bit : sigmap(wire))
- bitusers[bit]++;
- }
-
- for (auto cell : module->cells()) {
- if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_))) {
- RTLIL::SigSpec sig_y = sigmap(cell->getPort(ID::Y));
- for (int i = 0; i < GetSize(sig_y); i++)
- bit2mux[sig_y[i]] = cell_int_t(cell, i);
- }
- if (direct_dict.empty()) {
- if (cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_)))
- dff_cells.push_back(cell);
- } else {
- if (direct_dict.count(cell->type))
- dff_cells.push_back(cell);
- }
- for (auto conn : cell->connections()) {
- if (ct.cell_output(cell->type, conn.first))
- continue;
- for (auto bit : sigmap(conn.second))
- bitusers[bit]++;
- }
- }
- }
-
- patterns_t find_muxtree_feedback_patterns(RTLIL::SigBit d, RTLIL::SigBit q, pattern_t path)
- {
- patterns_t ret;
-
- if (d == q) {
- ret.insert(path);
- return ret;
- }
-
- if (bit2mux.count(d) == 0 || bitusers[d] > 1)
- return ret;
-
- cell_int_t mux_cell_int = bit2mux.at(d);
- RTLIL::SigSpec sig_a = sigmap(mux_cell_int.first->getPort(ID::A));
- RTLIL::SigSpec sig_b = sigmap(mux_cell_int.first->getPort(ID::B));
- RTLIL::SigSpec sig_s = sigmap(mux_cell_int.first->getPort(ID::S));
- int width = GetSize(sig_a), index = mux_cell_int.second;
-
- for (int i = 0; i < GetSize(sig_s); i++)
- if (path.count(sig_s[i]) && path.at(sig_s[i]))
- {
- ret = find_muxtree_feedback_patterns(sig_b[i*width + index], q, path);
-
- if (sig_b[i*width + index] == q) {
- RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::B);
- s[i*width + index] = RTLIL::Sx;
- mux_cell_int.first->setPort(ID::B, s);
- }
-
- return ret;
- }
-
- pattern_t path_else = path;
-
- for (int i = 0; i < GetSize(sig_s); i++)
- {
- if (path.count(sig_s[i]))
- continue;
-
- pattern_t path_this = path;
- path_else[sig_s[i]] = false;
- path_this[sig_s[i]] = true;
-
- for (auto &pat : find_muxtree_feedback_patterns(sig_b[i*width + index], q, path_this))
- ret.insert(pat);
-
- if (sig_b[i*width + index] == q) {
- RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::B);
- s[i*width + index] = RTLIL::Sx;
- mux_cell_int.first->setPort(ID::B, s);
- }
- }
-
- for (auto &pat : find_muxtree_feedback_patterns(sig_a[index], q, path_else))
- ret.insert(pat);
-
- if (sig_a[index] == q) {
- RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::A);
- s[index] = RTLIL::Sx;
- mux_cell_int.first->setPort(ID::A, s);
- }
-
- return ret;
- }
-
- void simplify_patterns(patterns_t&)
- {
- // TBD
- }
-
- RTLIL::SigSpec make_patterns_logic(patterns_t patterns, bool make_gates)
- {
- RTLIL::SigSpec or_input;
-
- for (auto pat : patterns)
- {
- RTLIL::SigSpec s1, s2;
- for (auto it : pat) {
- s1.append(it.first);
- s2.append(it.second);
- }
-
- RTLIL::SigSpec y = module->addWire(NEW_ID);
- RTLIL::Cell *c = module->addNe(NEW_ID, s1, s2, y);
-
- if (make_gates) {
- simplemap(module, c);
- module->remove(c);
- }
-
- or_input.append(y);
- }
-
- if (GetSize(or_input) == 0)
- return State::S1;
-
- if (GetSize(or_input) == 1)
- return or_input;
-
- RTLIL::SigSpec y = module->addWire(NEW_ID);
- RTLIL::Cell *c = module->addReduceAnd(NEW_ID, or_input, y);
-
- if (make_gates) {
- simplemap(module, c);
- module->remove(c);
- }
-
- return y;
- }
-
- void handle_dff_cell(RTLIL::Cell *dff_cell)
- {
- RTLIL::SigSpec sig_d = sigmap(dff_cell->getPort(ID::D));
- RTLIL::SigSpec sig_q = sigmap(dff_cell->getPort(ID::Q));
-
- std::map<patterns_t, std::set<int>> grouped_patterns;
- std::set<int> remaining_indices;
-
- for (int i = 0 ; i < GetSize(sig_d); i++) {
- patterns_t patterns = find_muxtree_feedback_patterns(sig_d[i], sig_q[i], pattern_t());
- if (!patterns.empty()) {
- simplify_patterns(patterns);
- grouped_patterns[patterns].insert(i);
- } else
- remaining_indices.insert(i);
- }
-
- for (auto &it : grouped_patterns) {
- RTLIL::SigSpec new_sig_d, new_sig_q;
- for (int i : it.second) {
- new_sig_d.append(sig_d[i]);
- new_sig_q.append(sig_q[i]);
- }
- if (!direct_dict.empty()) {
- log(" converting %s cell %s to %s for %s -> %s.\n", log_id(dff_cell->type), log_id(dff_cell), log_id(direct_dict.at(dff_cell->type)), log_signal(new_sig_d), log_signal(new_sig_q));
- dff_cell->setPort(ID::E, make_patterns_logic(it.first, true));
- dff_cell->type = direct_dict.at(dff_cell->type);
- } else
- if (dff_cell->type == ID($dff)) {
- RTLIL::Cell *new_cell = module->addDffe(NEW_ID, dff_cell->getPort(ID::CLK), make_patterns_logic(it.first, false),
- new_sig_d, new_sig_q, dff_cell->getParam(ID::CLK_POLARITY).as_bool(), true);
- log(" created $dffe cell %s for %s -> %s.\n", log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q));
- } else {
- RTLIL::Cell *new_cell = module->addDffeGate(NEW_ID, dff_cell->getPort(ID::C), make_patterns_logic(it.first, true),
- new_sig_d, new_sig_q, dff_cell->type == ID($_DFF_P_), true);
- log(" created %s cell %s for %s -> %s.\n", log_id(new_cell->type), log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q));
- }
- }
-
- if (!direct_dict.empty())
- return;
-
- if (remaining_indices.empty()) {
- log(" removing now obsolete cell %s.\n", log_id(dff_cell));
- module->remove(dff_cell);
- } else if (GetSize(remaining_indices) != GetSize(sig_d)) {
- log(" removing %d now obsolete bits from cell %s.\n", GetSize(sig_d) - GetSize(remaining_indices), log_id(dff_cell));
- RTLIL::SigSpec new_sig_d, new_sig_q;
- for (int i : remaining_indices) {
- new_sig_d.append(sig_d[i]);
- new_sig_q.append(sig_q[i]);
- }
- dff_cell->setPort(ID::D, new_sig_d);
- dff_cell->setPort(ID::Q, new_sig_q);
- dff_cell->setParam(ID::WIDTH, GetSize(remaining_indices));
- }
- }
-
- void run()
- {
- log("Transforming FF to FF+Enable cells in module %s:\n", log_id(module));
- for (auto dff_cell : dff_cells) {
- // log("Handling candidate %s:\n", log_id(dff_cell));
- handle_dff_cell(dff_cell);
- }
- }
-};
-
-struct Dff2dffePass : public Pass {
- Dff2dffePass() : Pass("dff2dffe", "transform $dff cells to $dffe cells") { }
- void help() YS_OVERRIDE
- {
- // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
- log("\n");
- log(" dff2dffe [options] [selection]\n");
- log("\n");
- log("This pass transforms $dff cells driven by a tree of multiplexers with one or\n");
- log("more feedback paths to $dffe cells. It also works on gate-level cells such as\n");
- log("$_DFF_P_, $_DFF_N_ and $_MUX_.\n");
- log("\n");
- log(" -unmap\n");
- log(" operate in the opposite direction: replace $dffe cells with combinations\n");
- log(" of $dff and $mux cells. the options below are ignored in unmap mode.\n");
- log("\n");
- log(" -unmap-mince N\n");
- log(" Same as -unmap but only unmap $dffe where the clock enable port\n");
- log(" signal is used by less $dffe than the specified number\n");
- log("\n");
- log(" -direct <internal_gate_type> <external_gate_type>\n");
- log(" map directly to external gate type. <internal_gate_type> can\n");
- log(" be any internal gate-level FF cell (except $_DFFE_??_). the\n");
- log(" <external_gate_type> is the cell type name for a cell with an\n");
- log(" identical interface to the <internal_gate_type>, except it\n");
- log(" also has an high-active enable port 'E'.\n");
- log(" Usually <external_gate_type> is an intermediate cell type\n");
- log(" that is then translated to the final type using 'techmap'.\n");
- log("\n");
- log(" -direct-match <pattern>\n");
- log(" like -direct for all DFF cell types matching the expression.\n");
- log(" this will use $__DFFE_* as <external_gate_type> matching the\n");
- log(" internal gate type $_DFF_*_, and $__DFFSE_* for those matching\n");
- log(" $_DFFS_*_, except for $_DFF_[NP]_, which is converted to \n");
- log(" $_DFFE_[NP]_.\n");
- log("\n");
- }
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
- {
- log_header(design, "Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n");
-
- bool unmap_mode = false;
- int min_ce_use = -1;
- dict<IdString, IdString> direct_dict;
-
- size_t argidx;
- for (argidx = 1; argidx < args.size(); argidx++) {
- if (args[argidx] == "-unmap") {
- unmap_mode = true;
- continue;
- }
- if (args[argidx] == "-unmap-mince" && argidx + 1 < args.size()) {
- unmap_mode = true;
- min_ce_use = atoi(args[++argidx].c_str());
- continue;
- }
- if (args[argidx] == "-direct" && argidx + 2 < args.size()) {
- string direct_from = RTLIL::escape_id(args[++argidx]);
- string direct_to = RTLIL::escape_id(args[++argidx]);
- direct_dict[direct_from] = direct_to;
- continue;
- }
- if (args[argidx] == "-direct-match" && argidx + 1 < args.size()) {
- bool found_match = false;
- const char *pattern = args[++argidx].c_str();
- if (patmatch(pattern, "$_DFF_P_" )) found_match = true, direct_dict[ID($_DFF_P_) ] = ID($_DFFE_PP_);
- if (patmatch(pattern, "$_DFF_N_" )) found_match = true, direct_dict[ID($_DFF_N_) ] = ID($_DFFE_NP_);
- if (patmatch(pattern, "$_DFF_NN0_")) found_match = true, direct_dict[ID($_DFF_NN0_)] = ID($__DFFE_NN0);
- if (patmatch(pattern, "$_DFF_NN1_")) found_match = true, direct_dict[ID($_DFF_NN1_)] = ID($__DFFE_NN1);
- if (patmatch(pattern, "$_DFF_NP0_")) found_match = true, direct_dict[ID($_DFF_NP0_)] = ID($__DFFE_NP0);
- if (patmatch(pattern, "$_DFF_NP1_")) found_match = true, direct_dict[ID($_DFF_NP1_)] = ID($__DFFE_NP1);
- if (patmatch(pattern, "$_DFF_PN0_")) found_match = true, direct_dict[ID($_DFF_PN0_)] = ID($__DFFE_PN0);
- if (patmatch(pattern, "$_DFF_PN1_")) found_match = true, direct_dict[ID($_DFF_PN1_)] = ID($__DFFE_PN1);
- if (patmatch(pattern, "$_DFF_PP0_")) found_match = true, direct_dict[ID($_DFF_PP0_)] = ID($__DFFE_PP0);
- if (patmatch(pattern, "$_DFF_PP1_")) found_match = true, direct_dict[ID($_DFF_PP1_)] = ID($__DFFE_PP1);
-
- if (patmatch(pattern, "$__DFFS_NN0_")) found_match = true, direct_dict[ID($__DFFS_NN0_)] = ID($__DFFSE_NN0);
- if (patmatch(pattern, "$__DFFS_NN1_")) found_match = true, direct_dict[ID($__DFFS_NN1_)] = ID($__DFFSE_NN1);
- if (patmatch(pattern, "$__DFFS_NP0_")) found_match = true, direct_dict[ID($__DFFS_NP0_)] = ID($__DFFSE_NP0);
- if (patmatch(pattern, "$__DFFS_NP1_")) found_match = true, direct_dict[ID($__DFFS_NP1_)] = ID($__DFFSE_NP1);
- if (patmatch(pattern, "$__DFFS_PN0_")) found_match = true, direct_dict[ID($__DFFS_PN0_)] = ID($__DFFSE_PN0);
- if (patmatch(pattern, "$__DFFS_PN1_")) found_match = true, direct_dict[ID($__DFFS_PN1_)] = ID($__DFFSE_PN1);
- if (patmatch(pattern, "$__DFFS_PP0_")) found_match = true, direct_dict[ID($__DFFS_PP0_)] = ID($__DFFSE_PP0);
- if (patmatch(pattern, "$__DFFS_PP1_")) found_match = true, direct_dict[ID($__DFFS_PP1_)] = ID($__DFFSE_PP1);
- if (!found_match)
- log_cmd_error("No cell types matched pattern '%s'.\n", pattern);
- continue;
- }
- break;
- }
- extra_args(args, argidx, design);
-
- if (!direct_dict.empty()) {
- log("Selected cell types for direct conversion:\n");
- for (auto &it : direct_dict)
- log(" %s -> %s\n", log_id(it.first), log_id(it.second));
- }
-
- for (auto mod : design->selected_modules())
- if (!mod->has_processes_warn())
- {
- if (unmap_mode) {
- SigMap sigmap(mod);
- for (auto cell : mod->selected_cells()) {
- if (cell->type == ID($dffe)) {
- if (min_ce_use >= 0) {
- int ce_use = 0;
- for (auto cell_other : mod->selected_cells()) {
- if (cell_other->type != cell->type)
- continue;
- if (sigmap(cell->getPort(ID::EN)) == sigmap(cell_other->getPort(ID::EN)))
- ce_use++;
- }
- if (ce_use >= min_ce_use)
- continue;
- }
-
- RTLIL::SigSpec tmp = mod->addWire(NEW_ID, GetSize(cell->getPort(ID::D)));
- mod->addDff(NEW_ID, cell->getPort(ID::CLK), tmp, cell->getPort(ID::Q), cell->getParam(ID::CLK_POLARITY).as_bool());
- if (cell->getParam(ID::EN_POLARITY).as_bool())
- mod->addMux(NEW_ID, cell->getPort(ID::Q), cell->getPort(ID::D), cell->getPort(ID::EN), tmp);
- else
- mod->addMux(NEW_ID, cell->getPort(ID::D), cell->getPort(ID::Q), cell->getPort(ID::EN), tmp);
- mod->remove(cell);
- continue;
- }
- if (cell->type.begins_with("$_DFFE_")) {
- if (min_ce_use >= 0) {
- int ce_use = 0;
- for (auto cell_other : mod->selected_cells()) {
- if (cell_other->type != cell->type)
- continue;
- if (sigmap(cell->getPort(ID::E)) == sigmap(cell_other->getPort(ID::E)))
- ce_use++;
- }
- if (ce_use >= min_ce_use)
- continue;
- }
-
- bool clk_pol = cell->type.compare(7, 1, "P") == 0;
- bool en_pol = cell->type.compare(8, 1, "P") == 0;
- RTLIL::SigSpec tmp = mod->addWire(NEW_ID);
- mod->addDff(NEW_ID, cell->getPort(ID::C), tmp, cell->getPort(ID::Q), clk_pol);
- if (en_pol)
- mod->addMux(NEW_ID, cell->getPort(ID::Q), cell->getPort(ID::D), cell->getPort(ID::E), tmp);
- else
- mod->addMux(NEW_ID, cell->getPort(ID::D), cell->getPort(ID::Q), cell->getPort(ID::E), tmp);
- mod->remove(cell);
- continue;
- }
- }
- continue;
- }
-
- Dff2dffeWorker worker(mod, direct_dict);
- worker.run();
- }
- }
-} Dff2dffePass;
-
-PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/dff2dffs.cc b/passes/techmap/dff2dffs.cc
deleted file mode 100644
index c155297d9..000000000
--- a/passes/techmap/dff2dffs.cc
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * yosys -- Yosys Open SYnthesis Suite
- *
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- * Copyright (C) 2018 David Shah <dave@ds0.me>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-#include "kernel/yosys.h"
-#include "kernel/sigtools.h"
-
-USING_YOSYS_NAMESPACE
-PRIVATE_NAMESPACE_BEGIN
-
-struct Dff2dffsPass : public Pass {
- Dff2dffsPass() : Pass("dff2dffs", "process sync set/reset with SR over CE priority") { }
- void help() YS_OVERRIDE
- {
- log("\n");
- log(" dff2dffs [options] [selection]\n");
- log("\n");
- log("Merge synchronous set/reset $_MUX_ cells to create $__DFFS_[NP][NP][01], to be run before\n");
- log("dff2dffe for SR over CE priority.\n");
- log("\n");
- log(" -match-init\n");
- log(" Disallow merging synchronous set/reset that has polarity opposite of the\n");
- log(" output wire's init attribute (if any).\n");
- log("\n");
- }
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
- {
- log_header(design, "Executing dff2dffs pass (merge synchronous set/reset into FF cells).\n");
-
- bool match_init = false;
- size_t argidx;
- for (argidx = 1; argidx < args.size(); argidx++)
- {
- // if (args[argidx] == "-singleton") {
- // singleton_mode = true;
- // continue;
- // }
- if (args[argidx] == "-match-init") {
- match_init = true;
- continue;
- }
- break;
- }
- extra_args(args, argidx, design);
-
- pool<IdString> dff_types;
- dff_types.insert(ID($_DFF_N_));
- dff_types.insert(ID($_DFF_P_));
-
- for (auto module : design->selected_modules())
- {
- log("Merging set/reset $_MUX_ cells into DFFs in %s.\n", log_id(module));
-
- SigMap sigmap(module);
- dict<SigBit, Cell*> sr_muxes;
- vector<Cell*> ff_cells;
-
- for (auto cell : module->selected_cells())
- {
- if (dff_types.count(cell->type)) {
- ff_cells.push_back(cell);
- continue;
- }
-
- if (cell->type != ID($_MUX_))
- continue;
-
- SigBit bit_a = sigmap(cell->getPort(ID::A));
- SigBit bit_b = sigmap(cell->getPort(ID::B));
-
- if (bit_a.wire == nullptr || bit_b.wire == nullptr)
- sr_muxes[sigmap(cell->getPort(ID::Y))] = cell;
- }
-
- for (auto cell : ff_cells)
- {
- SigSpec sig_d = cell->getPort(ID::D);
-
- if (GetSize(sig_d) < 1)
- continue;
-
- SigBit bit_d = sigmap(sig_d[0]);
-
- if (sr_muxes.count(bit_d) == 0)
- continue;
-
- Cell *mux_cell = sr_muxes.at(bit_d);
- SigBit bit_a = sigmap(mux_cell->getPort(ID::A));
- SigBit bit_b = sigmap(mux_cell->getPort(ID::B));
- SigBit bit_s = sigmap(mux_cell->getPort(ID::S));
-
- SigBit sr_val, sr_sig;
- bool invert_sr;
- sr_sig = bit_s;
- if (bit_a.wire == nullptr) {
- bit_d = bit_b;
- sr_val = bit_a;
- invert_sr = true;
- } else {
- log_assert(bit_b.wire == nullptr);
- bit_d = bit_a;
- sr_val = bit_b;
- invert_sr = false;
- }
-
- if (match_init) {
- SigBit bit_q = cell->getPort(ID::Q);
- if (bit_q.wire) {
- auto it = bit_q.wire->attributes.find(ID::init);
- if (it != bit_q.wire->attributes.end()) {
- auto init_val = it->second[bit_q.offset];
- if (init_val == State::S1 && sr_val != State::S1)
- continue;
- if (init_val == State::S0 && sr_val != State::S0)
- continue;
- }
- }
- }
-
- log(" Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell),
- log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type));
-
- if (sr_val == State::S1) {
- if (cell->type == ID($_DFF_N_)) {
- if (invert_sr) cell->type = ID($__DFFS_NN1_);
- else cell->type = ID($__DFFS_NP1_);
- } else {
- log_assert(cell->type == ID($_DFF_P_));
- if (invert_sr) cell->type = ID($__DFFS_PN1_);
- else cell->type = ID($__DFFS_PP1_);
- }
- } else {
- if (cell->type == ID($_DFF_N_)) {
- if (invert_sr) cell->type = ID($__DFFS_NN0_);
- else cell->type = ID($__DFFS_NP0_);
- } else {
- log_assert(cell->type == ID($_DFF_P_));
- if (invert_sr) cell->type = ID($__DFFS_PN0_);
- else cell->type = ID($__DFFS_PP0_);
- }
- }
- cell->setPort(ID::R, sr_sig);
- cell->setPort(ID::D, bit_d);
- }
- }
- }
-} Dff2dffsPass;
-
-PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc
index 35645582b..44af043db 100644
--- a/passes/techmap/dffinit.cc
+++ b/passes/techmap/dffinit.cc
@@ -19,13 +19,14 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
+#include "kernel/ffinit.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct DffinitPass : public Pass {
DffinitPass() : Pass("dffinit", "set INIT param on FF cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -54,7 +55,7 @@ struct DffinitPass : public Pass {
log(" the already defined initial value.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing DFFINIT pass (set INIT param on FF cells).\n");
@@ -94,29 +95,10 @@ struct DffinitPass : public Pass {
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
- dict<SigBit, State> init_bits;
- pool<SigBit> cleanup_bits;
- pool<SigBit> used_bits;
-
- for (auto wire : module->selected_wires()) {
- if (wire->attributes.count(ID::init)) {
- Const value = wire->attributes.at(ID::init);
- for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++)
- if (value[i] != State::Sx)
- init_bits[sigmap(SigBit(wire, i))] = value[i];
- }
- if (wire->port_output)
- for (auto bit : sigmap(wire))
- used_bits.insert(bit);
- }
+ FfInitVals initvals(&sigmap, module);
for (auto cell : module->selected_cells())
{
- for (auto it : cell->connections())
- if (!cell->known() || cell->input(it.first))
- for (auto bit : sigmap(it.second))
- used_bits.insert(bit);
-
if (ff_types.count(cell->type) == 0)
continue;
@@ -131,17 +113,18 @@ struct DffinitPass : public Pass {
if (cell->hasParam(it.second))
value = cell->getParam(it.second);
+ Const initval = initvals(sig);
+ initvals.remove_init(sig);
for (int i = 0; i < GetSize(sig); i++) {
- if (init_bits.count(sig[i]) == 0)
+ if (initval[i] == State::Sx)
continue;
while (GetSize(value.bits) <= i)
value.bits.push_back(State::S0);
- if (noreinit && value.bits[i] != State::Sx && value.bits[i] != init_bits.at(sig[i]))
+ if (noreinit && value.bits[i] != State::Sx && value.bits[i] != initval[i])
log_error("Trying to assign a different init value for %s.%s.%s which technically "
"have a conflicted init value.\n",
log_id(module), log_id(cell), log_id(it.second));
- value.bits[i] = init_bits.at(sig[i]);
- cleanup_bits.insert(sig[i]);
+ value.bits[i] = initval[i];
}
if (highlow_mode && GetSize(value) != 0) {
@@ -161,23 +144,6 @@ struct DffinitPass : public Pass {
}
}
}
-
- for (auto wire : module->selected_wires())
- if (wire->attributes.count(ID::init)) {
- Const &value = wire->attributes.at(ID::init);
- bool do_cleanup = true;
- for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) {
- SigBit bit = sigmap(SigBit(wire, i));
- if (cleanup_bits.count(bit) || !used_bits.count(bit))
- value[i] = State::Sx;
- else if (value[i] != State::Sx)
- do_cleanup = false;
- }
- if (do_cleanup) {
- log("Removing init attribute from wire %s.%s.\n", log_id(module), log_id(wire));
- wire->attributes.erase(ID::init);
- }
- }
}
}
} DffinitPass;
diff --git a/passes/techmap/dfflegalize.cc b/passes/techmap/dfflegalize.cc
new file mode 100644
index 000000000..c1e7e557d
--- /dev/null
+++ b/passes/techmap/dfflegalize.cc
@@ -0,0 +1,1323 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2020 Marcelina Kościelnicka <mwk@0x04.net>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "kernel/ffinit.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+enum FfType {
+ FF_DFF,
+ FF_DFFE,
+ FF_ADFF0,
+ FF_ADFF1,
+ FF_ADFFE0,
+ FF_ADFFE1,
+ FF_DFFSR,
+ FF_DFFSRE,
+ FF_SDFF0,
+ FF_SDFF1,
+ FF_SDFFE0,
+ FF_SDFFE1,
+ FF_SDFFCE0,
+ FF_SDFFCE1,
+ FF_SR,
+ FF_DLATCH,
+ FF_ADLATCH0,
+ FF_ADLATCH1,
+ FF_DLATCHSR,
+ NUM_FFTYPES,
+};
+
+enum FfNeg {
+ NEG_R = 0x1,
+ NEG_S = 0x2,
+ NEG_E = 0x4,
+ NEG_C = 0x8,
+ NUM_NEG = 0x10,
+};
+
+enum FfInit {
+ INIT_X = 0x1,
+ INIT_0 = 0x2,
+ INIT_1 = 0x4,
+};
+
+struct DffLegalizePass : public Pass {
+ DffLegalizePass() : Pass("dfflegalize", "convert FFs to types supported by the target") { }
+ void help() override
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" dfflegalize [options] [selection]\n");
+ log("\n");
+ log("Converts FFs to types supported by the target.\n");
+ log("\n");
+ log(" -cell <cell_type_pattern> <init_values>\n");
+ log(" specifies a supported group of FF cells. <cell_type_pattern>\n");
+ log(" is a yosys internal fine cell name, where ? characters can be\n");
+ log(" as a wildcard matching any character. <init_values> specifies\n");
+ log(" which initialization values these FF cells can support, and can\n");
+ log(" be one of:\n");
+ log("\n");
+ log(" - x (no init value supported)\n");
+ log(" - 0\n");
+ log(" - 1\n");
+ log(" - r (init value has to match reset value, only for some FF types)\n");
+ log(" - 01 (both 0 and 1 supported).\n");
+ log("\n");
+ log(" -mince <num>\n");
+ log(" specifies a minimum number of FFs that should be using any given\n");
+ log(" clock enable signal. If a clock enable signal doesn't meet this\n");
+ log(" threshold, it is unmapped into soft logic.\n");
+ log("\n");
+ log(" -minsrst <num>\n");
+ log(" specifies a minimum number of FFs that should be using any given\n");
+ log(" sync set/reset signal. If a sync set/reset signal doesn't meet this\n");
+ log(" threshold, it is unmapped into soft logic.\n");
+ log("\n");
+ log("The following cells are supported by this pass (ie. will be ingested,\n");
+ log("and can be specified as allowed targets):\n");
+ log("\n");
+ log("- $_DFF_[NP]_\n");
+ log("- $_DFFE_[NP][NP]_\n");
+ log("- $_DFF_[NP][NP][01]_\n");
+ log("- $_DFFE_[NP][NP][01][NP]_\n");
+ log("- $_DFFSR_[NP][NP][NP]_\n");
+ log("- $_DFFSRE_[NP][NP][NP][NP]_\n");
+ log("- $_SDFF_[NP][NP][01]_\n");
+ log("- $_SDFFE_[NP][NP][01][NP]_\n");
+ log("- $_SDFFCE_[NP][NP][01][NP]_\n");
+ log("- $_SR_[NP][NP]_\n");
+ log("- $_DLATCH_[NP]_\n");
+ log("- $_DLATCH_[NP][NP][01]_\n");
+ log("- $_DLATCHSR_[NP][NP][NP]_\n");
+ log("\n");
+ log("The following transformations are performed by this pass:");
+ log("\n");
+ log("- upconversion from a less capable cell to a more capable cell, if the less");
+ log(" capable cell is not supported (eg. dff -> dffe, or adff -> dffsr)");
+ log("\n");
+ log("- unmapping FFs with clock enable (due to unsupported cell type or -mince)");
+ log("\n");
+ log("- unmapping FFs with sync reset (due to unsupported cell type or -minsrst)");
+ log("\n");
+ log("- adding inverters on the control pins (due to unsupported polarity)");
+ log("\n");
+ log("- adding inverters on the D and Q pins and inverting the init/reset values\n");
+ log(" (due to unsupported init or reset value)");
+ log("\n");
+ log("- converting sr into adlatch (by tying D to 1 and using E as set input)");
+ log("\n");
+ log("- emulating unsupported dffsr cell by adff + adff + sr + mux");
+ log("\n");
+ log("- emulating unsupported dlatchsr cell by adlatch + adlatch + sr + mux");
+ log("\n");
+ log("- emulating adff when the (reset, init) value combination is unsupported by\n");
+ log(" dff + adff + dlatch + mux");
+ log("\n");
+ log("- emulating adlatch when the (reset, init) value combination is unsupported by\n");
+ log("- dlatch + adlatch + dlatch + mux");
+ log("\n");
+ log("If the pass is unable to realize a given cell type (eg. adff when only plain dff");
+ log("is available), an error is raised.");
+ }
+
+ // Table of all supported cell types.
+ // First index in the array is one of the FF_* values, second
+ // index is the set of negative-polarity inputs (OR of NEG_*
+ // values), and the value is the set of supported init values
+ // (OR of INIT_* values).
+ int supported_cells_neg[NUM_FFTYPES][NUM_NEG];
+ // Aggregated table ignoring signal polarity.
+ int supported_cells[NUM_FFTYPES];
+ // Aggregated for all *dff* cells.
+ int supported_dff;
+ // Aggregated for all dffsr* cells.
+ int supported_dffsr;
+ // Aggregated for all adff* cells.
+ int supported_adff0;
+ int supported_adff1;
+ // Aggregated for all sdff* cells.
+ int supported_sdff0;
+ int supported_sdff1;
+ // Aggregated for all ways to obtain a SR latch.
+ int supported_sr;
+ // Aggregated for all *dlatch* cells.
+ int supported_dlatch;
+
+ int mince;
+ int minsrst;
+
+ dict<SigBit, int> ce_used;
+ dict<SigBit, int> srst_used;
+
+ SigMap sigmap;
+ FfInitVals initvals;
+
+ int flip_initmask(int mask) {
+ int res = mask & INIT_X;
+ if (mask & INIT_0)
+ res |= INIT_1;
+ if (mask & INIT_1)
+ res |= INIT_0;
+ return res;
+ }
+
+ void handle_ff(Cell *cell) {
+ std::string type_str = cell->type.str();
+
+ FfType ff_type;
+ int ff_neg = 0;
+ SigSpec sig_d;
+ SigSpec sig_q;
+ SigSpec sig_c;
+ SigSpec sig_e;
+ SigSpec sig_r;
+ SigSpec sig_s;
+ bool has_srst = false;
+
+ if (cell->hasPort(ID::D))
+ sig_d = cell->getPort(ID::D);
+ if (cell->hasPort(ID::Q))
+ sig_q = cell->getPort(ID::Q);
+ if (cell->hasPort(ID::C))
+ sig_c = cell->getPort(ID::C);
+ if (cell->hasPort(ID::E))
+ sig_e = cell->getPort(ID::E);
+ if (cell->hasPort(ID::R))
+ sig_r = cell->getPort(ID::R);
+ if (cell->hasPort(ID::S))
+ sig_s = cell->getPort(ID::S);
+
+ if (type_str.substr(0, 5) == "$_SR_") {
+ ff_type = FF_SR;
+ if (type_str[5] == 'N')
+ ff_neg |= NEG_S;
+ if (type_str[6] == 'N')
+ ff_neg |= NEG_R;
+ } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 8) {
+ ff_type = FF_DFF;
+ if (type_str[6] == 'N')
+ ff_neg |= NEG_C;
+ } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 10) {
+ ff_type = FF_DFFE;
+ if (type_str[7] == 'N')
+ ff_neg |= NEG_C;
+ if (type_str[8] == 'N')
+ ff_neg |= NEG_E;
+ } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) {
+ ff_type = type_str[8] == '1' ? FF_ADFF1 : FF_ADFF0;
+ if (type_str[6] == 'N')
+ ff_neg |= NEG_C;
+ if (type_str[7] == 'N')
+ ff_neg |= NEG_R;
+ } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 12) {
+ ff_type = type_str[9] == '1' ? FF_ADFFE1 : FF_ADFFE0;
+ if (type_str[7] == 'N')
+ ff_neg |= NEG_C;
+ if (type_str[8] == 'N')
+ ff_neg |= NEG_R;
+ if (type_str[10] == 'N')
+ ff_neg |= NEG_E;
+ } else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) {
+ ff_type = FF_DFFSR;
+ if (type_str[8] == 'N')
+ ff_neg |= NEG_C;
+ if (type_str[9] == 'N')
+ ff_neg |= NEG_S;
+ if (type_str[10] == 'N')
+ ff_neg |= NEG_R;
+ } else if (type_str.substr(0, 9) == "$_DFFSRE_" && type_str.size() == 14) {
+ ff_type = FF_DFFSRE;
+ if (type_str[9] == 'N')
+ ff_neg |= NEG_C;
+ if (type_str[10] == 'N')
+ ff_neg |= NEG_S;
+ if (type_str[11] == 'N')
+ ff_neg |= NEG_R;
+ if (type_str[12] == 'N')
+ ff_neg |= NEG_E;
+ } else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) {
+ ff_type = type_str[9] == '1' ? FF_SDFF1 : FF_SDFF0;
+ if (type_str[7] == 'N')
+ ff_neg |= NEG_C;
+ if (type_str[8] == 'N')
+ ff_neg |= NEG_R;
+ has_srst = true;
+ } else if (type_str.substr(0, 8) == "$_SDFFE_" && type_str.size() == 13) {
+ ff_type = type_str[10] == '1' ? FF_SDFFE1 : FF_SDFFE0;
+ if (type_str[8] == 'N')
+ ff_neg |= NEG_C;
+ if (type_str[9] == 'N')
+ ff_neg |= NEG_R;
+ if (type_str[11] == 'N')
+ ff_neg |= NEG_E;
+ has_srst = true;
+ } else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) {
+ ff_type = type_str[11] == '1' ? FF_SDFFCE1 : FF_SDFFCE0;
+ if (type_str[9] == 'N')
+ ff_neg |= NEG_C;
+ if (type_str[10] == 'N')
+ ff_neg |= NEG_R;
+ if (type_str[12] == 'N')
+ ff_neg |= NEG_E;
+ has_srst = true;
+ } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) {
+ ff_type = FF_DLATCH;
+ if (type_str[9] == 'N')
+ ff_neg |= NEG_E;
+ } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) {
+ ff_type = type_str[11] == '1' ? FF_ADLATCH1 : FF_ADLATCH0;
+ if (type_str[9] == 'N')
+ ff_neg |= NEG_E;
+ if (type_str[10] == 'N')
+ ff_neg |= NEG_R;
+ } else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) {
+ ff_type = FF_DLATCHSR;
+ if (type_str[11] == 'N')
+ ff_neg |= NEG_E;
+ if (type_str[12] == 'N')
+ ff_neg |= NEG_S;
+ if (type_str[13] == 'N')
+ ff_neg |= NEG_R;
+ } else {
+ log_warning("Ignoring unknown ff type %s [%s.%s].\n", log_id(cell->type), log_id(cell->module->name), log_id(cell->name));
+ return;
+ }
+
+ State initval = initvals(sig_q[0]);
+
+ FfInit initmask = INIT_X;
+ if (initval == State::S0)
+ initmask = INIT_0;
+ else if (initval == State::S1)
+ initmask = INIT_1;
+ const char *reason;
+
+ bool kill_ce = mince && GetSize(sig_c) && GetSize(sig_e) && sig_e[0].wire && ce_used[sig_e[0]] < mince;
+ bool kill_srst = minsrst && has_srst && sig_r[0].wire && srst_used[sig_r[0]] < minsrst;
+
+ while (!(supported_cells[ff_type] & initmask) || kill_ce || kill_srst) {
+ // Well, cell is not directly supported. Decide how to deal with it.
+
+ if (ff_type == FF_DFF || ff_type == FF_DFFE) {
+ if (kill_ce) {
+ ff_type = FF_DFF;
+ goto unmap_enable;
+ }
+ if (!(supported_dff & initmask)) {
+ // This init value is not supported at all...
+ if (supported_dff & flip_initmask(initmask)) {
+ // The other one is, though. Negate D, Q, and init.
+flip_dqi:
+ if (initval == State::S0) {
+ initval = State::S1;
+ initmask = INIT_1;
+ } else if (initval == State::S1) {
+ initval = State::S0;
+ initmask = INIT_0;
+ }
+ if (ff_type != FF_SR)
+ sig_d = cell->module->NotGate(NEW_ID, sig_d[0]);
+ SigBit new_q = SigSpec(cell->module->addWire(NEW_ID))[0];
+ cell->module->addNotGate(NEW_ID, new_q, sig_q[0]);
+ initvals.remove_init(sig_q[0]);
+ initvals.set_init(new_q, initval);
+ sig_q = new_q;
+ continue;
+ }
+ if (!supported_dff)
+ reason = "dffs are not supported";
+ else
+ reason = "initialized dffs are not supported";
+ goto error;
+ }
+
+ // Some DFF is supported with this init val. Just pick a type.
+ if (ff_type == FF_DFF) {
+ // Try adding a set or reset pin.
+ for (auto new_type: {FF_SDFF0, FF_SDFF1, FF_ADFF0, FF_ADFF1})
+ if (supported_cells[new_type] & initmask) {
+ ff_type = new_type;
+ sig_r = State::S0;
+ goto cell_ok;
+ }
+ // Try adding both.
+ if (supported_cells[FF_DFFSR] & initmask) {
+ ff_type = FF_DFFSR;
+ sig_r = State::S0;
+ sig_s = State::S0;
+ break;
+ }
+ // Nope. Will need to add enable and go the DFFE route.
+ sig_e = State::S1;
+ if (supported_cells[FF_DFFE] & initmask) {
+ ff_type = FF_DFFE;
+ break;
+ }
+ }
+ // Try adding a set or reset pin.
+ for (auto new_type: {FF_SDFFE0, FF_SDFFE1, FF_SDFFCE0, FF_SDFFCE1, FF_ADFFE0, FF_ADFFE1})
+ if (supported_cells[new_type] & initmask) {
+ ff_type = new_type;
+ sig_r = State::S0;
+ goto cell_ok;
+ }
+ // Try adding both.
+ if (supported_cells[FF_DFFSRE] & initmask) {
+ ff_type = FF_DFFSRE;
+ sig_r = State::S0;
+ sig_s = State::S0;
+ break;
+ }
+
+ // Seems that no DFFs with enable are supported.
+ // The enable input needs to be unmapped.
+ // This should not be reached if we started from plain DFF.
+ log_assert(ff_type == FF_DFFE);
+ ff_type = FF_DFF;
+unmap_enable:
+ if (ff_neg & NEG_E)
+ sig_d = cell->module->MuxGate(NEW_ID, sig_d[0], sig_q[0], sig_e[0]);
+ else
+ sig_d = cell->module->MuxGate(NEW_ID, sig_q[0], sig_d[0], sig_e[0]);
+ ff_neg &= ~NEG_E;
+ sig_e = SigSpec();
+ kill_ce = false;
+ // Now try again as plain DFF.
+ continue;
+ } else if (ff_type == FF_ADFF0 || ff_type == FF_ADFF1 || ff_type == FF_ADFFE0 || ff_type == FF_ADFFE1) {
+ bool has_set = ff_type == FF_ADFF1 || ff_type == FF_ADFFE1;
+ bool has_en = ff_type == FF_ADFFE0 || ff_type == FF_ADFFE1;
+ if (kill_ce) {
+ ff_type = has_set ? FF_ADFF1 : FF_ADFF0;
+ goto unmap_enable;
+ }
+ if (!has_en && (supported_cells[has_set ? FF_ADFFE1 : FF_ADFFE0] & initmask)) {
+ // Just add enable.
+ sig_e = State::S1;
+ ff_type = has_set ? FF_ADFFE1 : FF_ADFFE0;
+ break;
+ }
+ if (supported_cells[has_en ? FF_DFFSRE : FF_DFFSR] & initmask) {
+adff_to_dffsr:
+ // Throw in a set/reset, retry in DFFSR/DFFSRE branch.
+ if (has_set) {
+ sig_s = sig_r;
+ sig_r = State::S0;
+ if (ff_neg & NEG_R) {
+ ff_neg &= ~NEG_R;
+ ff_neg |= NEG_S;
+ }
+ } else {
+ sig_s = State::S0;
+ }
+ if (has_en)
+ ff_type = FF_DFFSRE;
+ else
+ ff_type = FF_DFFSR;
+ continue;
+ }
+ if (has_en && (supported_cells[has_set ? FF_ADFF1 : FF_ADFF0] & initmask)) {
+ // Unmap enable.
+ ff_type = has_set ? FF_ADFF1 : FF_ADFF0;
+ goto unmap_enable;
+ }
+ if (supported_dffsr & initmask) {
+ goto adff_to_dffsr;
+ }
+ log_assert(!((has_set ? supported_adff1 : supported_adff0) & initmask));
+ // Alright, so this particular combination of initval and
+ // resetval is not natively supported. First, try flipping
+ // them both to see whether this helps.
+ int flipmask = flip_initmask(initmask);
+ if ((has_set ? supported_adff0 : supported_adff1) & flipmask) {
+ // Checks out, do it.
+ ff_type = has_en ? (has_set ? FF_ADFFE0 : FF_ADFFE1) : (has_set ? FF_ADFF0 : FF_ADFF1);
+ goto flip_dqi;
+ }
+
+ if (!supported_adff0 && !supported_adff1) {
+ reason = "dffs with async set or reset are not supported";
+ goto error;
+ }
+ if (!(supported_dff & ~INIT_X)) {
+ reason = "initialized dffs are not supported";
+ goto error;
+ }
+ // If we got here, initialized dff is supported, but not this
+ // particular reset+init combination (nor its negation).
+ // The only hope left is breaking down to adff + dff + dlatch + mux.
+ if (!(supported_dlatch & ~INIT_X)) {
+ reason = "unsupported initial value and async reset value combination";
+ goto error;
+ }
+
+ // If we have to unmap enable anyway, do it before breakdown.
+ if (has_en && !supported_cells[FF_ADFFE0] && !supported_cells[FF_ADFFE1]) {
+ ff_type = has_set ? FF_ADFF1 : FF_ADFF0;
+ goto unmap_enable;
+ }
+
+ log_warning("Emulating mismatched async reset and init with several FFs and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name));
+ initvals.remove_init(sig_q[0]);
+ Wire *adff_q = cell->module->addWire(NEW_ID);
+ Wire *dff_q = cell->module->addWire(NEW_ID);
+ Wire *sel_q = cell->module->addWire(NEW_ID);
+ initvals.set_init(SigBit(dff_q, 0), initval);
+ initvals.set_init(SigBit(sel_q, 0), State::S0);
+ Cell *cell_dff;
+ Cell *cell_adff;
+ Cell *cell_sel;
+ if (!has_en) {
+ cell_dff = cell->module->addDffGate(NEW_ID, sig_c, sig_d, dff_q, !(ff_neg & NEG_C));
+ cell_adff = cell->module->addAdffGate(NEW_ID, sig_c, sig_r, sig_d, adff_q, has_set, !(ff_neg & NEG_C), !(ff_neg & NEG_R));
+ } else {
+ cell_dff = cell->module->addDffeGate(NEW_ID, sig_c, sig_e, sig_d, dff_q, !(ff_neg & NEG_C), !(ff_neg & NEG_E));
+ cell_adff = cell->module->addAdffeGate(NEW_ID, sig_c, sig_e, sig_r, sig_d, adff_q, has_set, !(ff_neg & NEG_C), !(ff_neg & NEG_E), !(ff_neg & NEG_R));
+ }
+ cell_sel = cell->module->addDlatchGate(NEW_ID, sig_r, State::S1, sel_q, !(ff_neg & NEG_R));
+ cell->module->addMuxGate(NEW_ID, dff_q, adff_q, sel_q, sig_q);
+
+ // Bye, cell.
+ cell->module->remove(cell);
+ handle_ff(cell_dff);
+ handle_ff(cell_adff);
+ handle_ff(cell_sel);
+ return;
+ } else if (ff_type == FF_DFFSR || ff_type == FF_DFFSRE) {
+ if (kill_ce) {
+ ff_type = FF_DFFSR;
+ goto unmap_enable;
+ }
+ // First, see if mapping/unmapping enable will help.
+ if (supported_cells[FF_DFFSRE] & initmask) {
+ ff_type = FF_DFFSRE;
+ sig_e = State::S1;
+ break;
+ }
+ if (supported_cells[FF_DFFSR] & initmask) {
+ ff_type = FF_DFFSR;
+ goto unmap_enable;
+ }
+ if (supported_dffsr & flip_initmask(initmask)) {
+flip_dqisr:;
+ log_warning("Flipping D/Q/init and inserting set/reset fixup to handle init value on %s.%s [%s]\n", log_id(cell->module->name), log_id(cell->name), log_id(cell->type));
+ SigSpec new_r;
+ bool neg_r = (ff_neg & NEG_R);
+ bool neg_s = (ff_neg & NEG_S);
+ if (!(ff_neg & NEG_S)) {
+ if (!(ff_neg & NEG_R))
+ new_r = cell->module->AndnotGate(NEW_ID, sig_s, sig_r);
+ else
+ new_r = cell->module->AndGate(NEW_ID, sig_s, sig_r);
+ } else {
+ if (!(ff_neg & NEG_R))
+ new_r = cell->module->OrGate(NEW_ID, sig_s, sig_r);
+ else
+ new_r = cell->module->OrnotGate(NEW_ID, sig_s, sig_r);
+ }
+ ff_neg &= ~(NEG_R | NEG_S);
+ if (neg_r)
+ ff_neg |= NEG_S;
+ if (neg_s)
+ ff_neg |= NEG_R;
+ sig_s = sig_r;
+ sig_r = new_r;
+ goto flip_dqi;
+ }
+ // No native DFFSR. However, if we can conjure
+ // a SR latch and ADFF, it can still be emulated.
+ int flipmask = flip_initmask(initmask);
+ bool init0 = true;
+ bool init1 = true;
+ State initsel = State::Sx;
+ if (((supported_adff0 & initmask) || (supported_adff1 & flipmask)) && ((supported_adff1 & initmask) || (supported_adff0 & flipmask)) && supported_sr) {
+ // OK
+ } else if (((supported_adff0 & initmask) || (supported_adff1 & flipmask)) && (supported_sr & INIT_0)) {
+ init1 = false;
+ initsel = State::S0;
+ } else if (((supported_adff1 & initmask) || (supported_adff0 & flipmask)) && (supported_sr & INIT_1)) {
+ init0 = false;
+ initsel = State::S1;
+ } else if (((supported_adff0 & initmask) || (supported_adff1 & flipmask)) && (supported_sr & INIT_1)) {
+ init1 = false;
+ initsel = State::S0;
+ } else if (((supported_adff1 & initmask) || (supported_adff0 & flipmask)) && (supported_sr & INIT_0)) {
+ init0 = false;
+ initsel = State::S1;
+ } else {
+ if (!supported_dffsr)
+ reason = "dffs with async set and reset are not supported";
+ else
+ reason = "initialized dffs with async set and reset are not supported";
+ goto error;
+ }
+
+ // If we have to unmap enable anyway, do it before breakdown.
+ if (ff_type == FF_DFFSRE && !supported_cells[FF_ADFFE0] && !supported_cells[FF_ADFFE1]) {
+ ff_type = FF_DFFSR;
+ goto unmap_enable;
+ }
+
+ log_warning("Emulating async set + reset with several FFs and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name));
+ initvals.remove_init(sig_q[0]);
+ Wire *adff0_q = cell->module->addWire(NEW_ID);
+ Wire *adff1_q = cell->module->addWire(NEW_ID);
+ Wire *sel_q = cell->module->addWire(NEW_ID);
+ if (init0)
+ initvals.set_init(SigBit(adff0_q, 0), initval);
+ if (init1)
+ initvals.set_init(SigBit(adff1_q, 0), initval);
+ initvals.set_init(SigBit(sel_q, 0), initsel);
+ Cell *cell_adff0;
+ Cell *cell_adff1;
+ Cell *cell_sel;
+ if (ff_type == FF_DFFSR) {
+ cell_adff0 = cell->module->addAdffGate(NEW_ID, sig_c, sig_r, sig_d, adff0_q, false, !(ff_neg & NEG_C), !(ff_neg & NEG_R));
+ cell_adff1 = cell->module->addAdffGate(NEW_ID, sig_c, sig_s, sig_d, adff1_q, true, !(ff_neg & NEG_C), !(ff_neg & NEG_S));
+ } else {
+ cell_adff0 = cell->module->addAdffeGate(NEW_ID, sig_c, sig_e, sig_r, sig_d, adff0_q, false, !(ff_neg & NEG_C), !(ff_neg & NEG_E), !(ff_neg & NEG_R));
+ cell_adff1 = cell->module->addAdffeGate(NEW_ID, sig_c, sig_e, sig_s, sig_d, adff1_q, true, !(ff_neg & NEG_C), !(ff_neg & NEG_E), !(ff_neg & NEG_S));
+ }
+ cell_sel = cell->module->addSrGate(NEW_ID, sig_s, sig_r, sel_q, !(ff_neg & NEG_S), !(ff_neg & NEG_R));
+ cell->module->addMuxGate(NEW_ID, adff0_q, adff1_q, sel_q, sig_q);
+
+ // Bye, cell.
+ cell->module->remove(cell);
+ handle_ff(cell_adff0);
+ handle_ff(cell_adff1);
+ handle_ff(cell_sel);
+ return;
+ } else if (ff_type == FF_SR) {
+ if (supported_cells[FF_ADLATCH0] & initmask || supported_cells[FF_ADLATCH1] & flip_initmask(initmask)) {
+ // Convert to ADLATCH0. May get converted to ADLATCH1.
+ ff_type = FF_ADLATCH0;
+ sig_e = sig_s;
+ sig_d = State::S1;
+ if (ff_neg & NEG_S) {
+ ff_neg &= ~NEG_S;
+ ff_neg |= NEG_E;
+ }
+ continue;
+ } else if (supported_cells[FF_DLATCHSR] & initmask) {
+ // Upgrade to DLATCHSR.
+ ff_type = FF_DLATCHSR;
+ sig_e = State::S0;
+ sig_d = State::Sx;
+ break;
+ } else if (supported_dffsr & initmask) {
+ // Upgrade to DFFSR. May get further upgraded to DFFSRE.
+ ff_type = FF_DFFSR;
+ sig_c = State::S0;
+ sig_d = State::Sx;
+ continue;
+ } else if (supported_sr & flip_initmask(initmask)) {
+ goto flip_dqisr;
+ } else {
+ if (!supported_sr)
+ reason = "sr latches are not supported";
+ else
+ reason = "initialized sr latches are not supported";
+ goto error;
+ }
+ } else if (ff_type == FF_DLATCH) {
+ if (!(supported_dlatch & initmask)) {
+ // This init value is not supported at all...
+ if (supported_dlatch & flip_initmask(initmask))
+ goto flip_dqi;
+
+ if ((sig_d == State::S0 && (supported_adff0 & initmask)) ||
+ (sig_d == State::S1 && (supported_adff1 & initmask)) ||
+ (sig_d == State::S0 && (supported_adff1 & flip_initmask(initmask))) ||
+ (sig_d == State::S1 && (supported_adff0 & flip_initmask(initmask)))
+ ) {
+ // Special case: const-D dlatch can be converted into adff with const clock.
+ ff_type = (sig_d == State::S0) ? FF_ADFF0 : FF_ADFF1;
+ if (ff_neg & NEG_E) {
+ ff_neg &= ~NEG_E;
+ ff_neg |= NEG_R;
+ }
+ sig_r = sig_e;
+ sig_d = State::Sx;
+ sig_c = State::S1;
+ continue;
+ }
+
+ if (!supported_dlatch)
+ reason = "dlatch are not supported";
+ else
+ reason = "initialized dlatch are not supported";
+ goto error;
+ }
+
+ // Some DLATCH is supported with this init val. Just pick a type.
+ if (supported_cells[FF_ADLATCH0] & initmask) {
+ ff_type = FF_ADLATCH0;
+ sig_r = State::S0;
+ break;
+ }
+ if (supported_cells[FF_ADLATCH1] & initmask) {
+ ff_type = FF_ADLATCH1;
+ sig_r = State::S0;
+ break;
+ }
+ if (supported_cells[FF_DLATCHSR] & initmask) {
+ ff_type = FF_DLATCHSR;
+ sig_r = State::S0;
+ sig_s = State::S0;
+ break;
+ }
+ log_assert(0);
+ } else if (ff_type == FF_ADLATCH0 || ff_type == FF_ADLATCH1) {
+ if (supported_cells[FF_DLATCHSR] & initmask) {
+ if (ff_type == FF_ADLATCH1) {
+ sig_s = sig_r;
+ sig_r = State::S0;
+ if (ff_neg & NEG_R) {
+ ff_neg &= ~NEG_R;
+ ff_neg |= NEG_S;
+ }
+ } else {
+ sig_s = State::S0;
+ }
+ ff_type = FF_DLATCHSR;
+ break;
+ }
+ FfType flip_type = ff_type == FF_ADLATCH0 ? FF_ADLATCH1 : FF_ADLATCH0;
+ if ((supported_cells[flip_type] | supported_cells[FF_DLATCHSR]) & flip_initmask(initmask)) {
+ ff_type = flip_type;
+ goto flip_dqi;
+ }
+
+ if (!supported_cells[FF_ADLATCH0] && !supported_cells[FF_ADLATCH1] && !supported_cells[FF_DLATCHSR]) {
+ reason = "dlatch with async set or reset are not supported";
+ goto error;
+ }
+ if (!(supported_dlatch & ~INIT_X)) {
+ reason = "initialized dlatch are not supported";
+ goto error;
+ }
+
+ if (!(supported_dlatch & ~INIT_X)) {
+ reason = "initialized dlatch are not supported";
+ goto error;
+ }
+ // If we got here, initialized dlatch is supported, but not this
+ // particular reset+init combination (nor its negation).
+ // The only hope left is breaking down to adff + dff + dlatch + mux.
+
+ log_warning("Emulating mismatched async reset and init with several latches and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name));
+ initvals.remove_init(sig_q[0]);
+ Wire *adlatch_q = cell->module->addWire(NEW_ID);
+ Wire *dlatch_q = cell->module->addWire(NEW_ID);
+ Wire *sel_q = cell->module->addWire(NEW_ID);
+ initvals.set_init(SigBit(dlatch_q, 0), initval);
+ initvals.set_init(SigBit(sel_q, 0), State::S0);
+ Cell *cell_dlatch;
+ Cell *cell_adlatch;
+ Cell *cell_sel;
+ cell_dlatch = cell->module->addDlatchGate(NEW_ID, sig_e, sig_d, dlatch_q, !(ff_neg & NEG_E));
+ cell_adlatch = cell->module->addAdlatchGate(NEW_ID, sig_e, sig_r, sig_d, adlatch_q, ff_type == FF_ADLATCH1, !(ff_neg & NEG_E), !(ff_neg & NEG_R));
+ cell_sel = cell->module->addDlatchGate(NEW_ID, sig_r, State::S1, sel_q, !(ff_neg & NEG_R));
+ cell->module->addMuxGate(NEW_ID, dlatch_q, adlatch_q, sel_q, sig_q);
+
+ // Bye, cell.
+ cell->module->remove(cell);
+ handle_ff(cell_dlatch);
+ handle_ff(cell_adlatch);
+ handle_ff(cell_sel);
+ return;
+ } else if (ff_type == FF_DLATCHSR) {
+ if (supported_cells[FF_DLATCHSR] & flip_initmask(initmask)) {
+ goto flip_dqisr;
+ }
+ // No native DFFSR. However, if we can conjure
+ // a SR latch and ADFF, it can still be emulated.
+ int flipmask = flip_initmask(initmask);
+ bool init0 = true;
+ bool init1 = true;
+ State initsel = State::Sx;
+ if (((supported_cells[FF_ADLATCH0] & initmask) || (supported_cells[FF_ADLATCH1] & flipmask)) && ((supported_cells[FF_ADLATCH1] & initmask) || (supported_cells[FF_ADLATCH0] & flipmask)) && supported_sr) {
+ // OK
+ } else if (((supported_cells[FF_ADLATCH0] & initmask) || (supported_cells[FF_ADLATCH1] & flipmask)) && (supported_sr & INIT_0)) {
+ init1 = false;
+ initsel = State::S0;
+ } else if (((supported_cells[FF_ADLATCH1] & initmask) || (supported_cells[FF_ADLATCH0] & flipmask)) && (supported_sr & INIT_1)) {
+ init0 = false;
+ initsel = State::S1;
+ } else if (((supported_cells[FF_ADLATCH0] & initmask) || (supported_cells[FF_ADLATCH1] & flipmask)) && (supported_sr & INIT_1)) {
+ init1 = false;
+ initsel = State::S0;
+ } else if (((supported_cells[FF_ADLATCH1] & initmask) || (supported_cells[FF_ADLATCH0] & flipmask)) && (supported_sr & INIT_0)) {
+ init0 = false;
+ initsel = State::S1;
+ } else {
+ if (!supported_cells[FF_DLATCHSR])
+ reason = "dlatch with async set and reset are not supported";
+ else
+ reason = "initialized dlatch with async set and reset are not supported";
+ goto error;
+ }
+
+ log_warning("Emulating async set + reset with several latches and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name));
+ initvals.remove_init(sig_q[0]);
+ Wire *adlatch0_q = cell->module->addWire(NEW_ID);
+ Wire *adlatch1_q = cell->module->addWire(NEW_ID);
+ Wire *sel_q = cell->module->addWire(NEW_ID);
+ if (init0)
+ initvals.set_init(SigBit(adlatch0_q, 0), initval);
+ if (init1)
+ initvals.set_init(SigBit(adlatch1_q, 0), initval);
+ initvals.set_init(SigBit(sel_q, 0), initsel);
+ Cell *cell_adlatch0;
+ Cell *cell_adlatch1;
+ Cell *cell_sel;
+ cell_adlatch0 = cell->module->addAdlatchGate(NEW_ID, sig_e, sig_r, sig_d, adlatch0_q, false, !(ff_neg & NEG_E), !(ff_neg & NEG_R));
+ cell_adlatch1 = cell->module->addAdlatchGate(NEW_ID, sig_e, sig_s, sig_d, adlatch1_q, true, !(ff_neg & NEG_E), !(ff_neg & NEG_S));
+ cell_sel = cell->module->addSrGate(NEW_ID, sig_s, sig_r, sel_q, !(ff_neg & NEG_S), !(ff_neg & NEG_R));
+ cell->module->addMuxGate(NEW_ID, adlatch0_q, adlatch1_q, sel_q, sig_q);
+
+ // Bye, cell.
+ cell->module->remove(cell);
+ handle_ff(cell_adlatch0);
+ handle_ff(cell_adlatch1);
+ handle_ff(cell_sel);
+ return;
+ } else if (ff_type == FF_SDFF0 || ff_type == FF_SDFF1 || ff_type == FF_SDFFE0 || ff_type == FF_SDFFE1 || ff_type == FF_SDFFCE0 || ff_type == FF_SDFFCE1) {
+ bool has_set = ff_type == FF_SDFF1 || ff_type == FF_SDFFE1 || ff_type == FF_SDFFCE1;
+ bool has_en = ff_type == FF_SDFFE0 || ff_type == FF_SDFFE1;
+ bool has_ce = ff_type == FF_SDFFCE0 || ff_type == FF_SDFFCE1;
+
+ if (has_en) {
+ if (kill_ce || kill_srst) {
+ ff_type = has_set ? FF_SDFF1 : FF_SDFF0;
+ goto unmap_enable;
+ }
+ } else if (has_ce) {
+ if (kill_ce || kill_srst)
+ goto unmap_srst;
+ } else {
+ log_assert(!kill_ce);
+ if (kill_srst)
+ goto unmap_srst;
+ }
+
+ if (!has_ce) {
+ if (!has_en && (supported_cells[has_set ? FF_SDFFE1 : FF_SDFFE0] & initmask)) {
+ // Just add enable.
+ sig_e = State::S1;
+ ff_type = has_set ? FF_SDFFE1 : FF_SDFFE0;
+ break;
+ }
+ if (!has_en && (supported_cells[has_set ? FF_SDFFCE1 : FF_SDFFCE0] & initmask)) {
+ // Just add enable.
+ sig_e = State::S1;
+ ff_type = has_set ? FF_SDFFCE1 : FF_SDFFCE0;
+ break;
+ }
+ if (has_en && (supported_cells[has_set ? FF_SDFFCE1 : FF_SDFFCE0] & initmask)) {
+ // Convert sdffe to sdffce
+ if (!(ff_neg & NEG_E)) {
+ if (!(ff_neg & NEG_R))
+ sig_e = cell->module->OrGate(NEW_ID, sig_e, sig_r);
+ else
+ sig_e = cell->module->OrnotGate(NEW_ID, sig_e, sig_r);
+ } else {
+ if (!(ff_neg & NEG_R))
+ sig_e = cell->module->AndnotGate(NEW_ID, sig_e, sig_r);
+ else
+ sig_e = cell->module->AndGate(NEW_ID, sig_e, sig_r);
+ }
+ ff_type = has_set ? FF_SDFFCE1 : FF_SDFFCE0;
+ break;
+ }
+ if (has_en && (supported_cells[has_set ? FF_SDFF1 : FF_SDFF0] & initmask)) {
+ // Unmap enable.
+ ff_type = has_set ? FF_SDFF1 : FF_SDFF0;
+ goto unmap_enable;
+ }
+ log_assert(!((has_set ? supported_sdff1 : supported_sdff0) & initmask));
+ } else {
+ if ((has_set ? supported_sdff1 : supported_sdff0) & initmask) {
+ // Convert sdffce to sdffe, which may be further converted to sdff.
+ if (!(ff_neg & NEG_R)) {
+ if (!(ff_neg & NEG_E))
+ sig_r = cell->module->AndGate(NEW_ID, sig_r, sig_e);
+ else
+ sig_r = cell->module->AndnotGate(NEW_ID, sig_r, sig_e);
+ } else {
+ if (!(ff_neg & NEG_E))
+ sig_r = cell->module->OrnotGate(NEW_ID, sig_r, sig_e);
+ else
+ sig_r = cell->module->OrGate(NEW_ID, sig_r, sig_e);
+ }
+ ff_type = has_set ? FF_SDFFE1 : FF_SDFFE0;
+ continue;
+ }
+ }
+ // Alright, so this particular combination of initval and
+ // resetval is not natively supported. First, try flipping
+ // them both to see whether this helps.
+ if ((has_set ? supported_sdff0 : supported_sdff1) & flip_initmask(initmask)) {
+ // Checks out, do it.
+ ff_type = has_ce ? (has_set ? FF_SDFFCE0 : FF_SDFFCE1) : has_en ? (has_set ? FF_SDFFE0 : FF_SDFFE1) : (has_set ? FF_SDFF0 : FF_SDFF1);
+ goto flip_dqi;
+ }
+
+ // Nope. No way to get SDFF* of the right kind, so unmap it.
+ // For SDFFE, the enable has to be unmapped first.
+ if (has_en) {
+ ff_type = has_set ? FF_SDFF1 : FF_SDFF0;
+ goto unmap_enable;
+ }
+unmap_srst:
+ if (has_ce)
+ ff_type = FF_DFFE;
+ else
+ ff_type = FF_DFF;
+ if (ff_neg & NEG_R)
+ sig_d = cell->module->MuxGate(NEW_ID, has_set ? State::S1 : State::S0, sig_d[0], sig_r[0]);
+ else
+ sig_d = cell->module->MuxGate(NEW_ID, sig_d[0], has_set ? State::S1 : State::S0, sig_r[0]);
+ ff_neg &= ~NEG_R;
+ sig_r = SigSpec();
+ kill_srst = false;
+ continue;
+ } else {
+ log_assert(0);
+ }
+ }
+cell_ok:
+
+ if (!(supported_cells_neg[ff_type][ff_neg] & initmask)) {
+ // Cell is supported, but not with those polarities.
+ // Will need to add some inverters.
+
+ // Find the smallest value that xored with the neg mask
+ // results in a supported one — this results in preferentially
+ // inverting resets before clocks, etc.
+ int xneg;
+ for (xneg = 0; xneg < NUM_NEG; xneg++)
+ if (supported_cells_neg[ff_type][ff_neg ^ xneg] & initmask)
+ break;
+ log_assert(xneg < NUM_NEG);
+ if (xneg & NEG_R)
+ sig_r = cell->module->NotGate(NEW_ID, sig_r[0]);
+ if (xneg & NEG_S)
+ sig_s = cell->module->NotGate(NEW_ID, sig_s[0]);
+ if (xneg & NEG_E)
+ sig_e = cell->module->NotGate(NEW_ID, sig_e[0]);
+ if (xneg & NEG_C)
+ sig_c = cell->module->NotGate(NEW_ID, sig_c[0]);
+ ff_neg ^= xneg;
+ }
+
+ cell->unsetPort(ID::D);
+ cell->unsetPort(ID::Q);
+ cell->unsetPort(ID::C);
+ cell->unsetPort(ID::E);
+ cell->unsetPort(ID::S);
+ cell->unsetPort(ID::R);
+ switch (ff_type) {
+ case FF_DFF:
+ cell->type = IdString(stringf("$_DFF_%c_",
+ (ff_neg & NEG_C) ? 'N' : 'P'
+ ));
+ cell->setPort(ID::D, sig_d);
+ cell->setPort(ID::Q, sig_q);
+ cell->setPort(ID::C, sig_c);
+ break;
+ case FF_DFFE:
+ cell->type = IdString(stringf("$_DFFE_%c%c_",
+ (ff_neg & NEG_C) ? 'N' : 'P',
+ (ff_neg & NEG_E) ? 'N' : 'P'
+ ));
+ cell->setPort(ID::D, sig_d);
+ cell->setPort(ID::Q, sig_q);
+ cell->setPort(ID::C, sig_c);
+ cell->setPort(ID::E, sig_e);
+ break;
+ case FF_ADFF0:
+ case FF_ADFF1:
+ cell->type = IdString(stringf("$_DFF_%c%c%c_",
+ (ff_neg & NEG_C) ? 'N' : 'P',
+ (ff_neg & NEG_R) ? 'N' : 'P',
+ (ff_type == FF_ADFF1) ? '1' : '0'
+ ));
+ cell->setPort(ID::D, sig_d);
+ cell->setPort(ID::Q, sig_q);
+ cell->setPort(ID::C, sig_c);
+ cell->setPort(ID::R, sig_r);
+ break;
+ case FF_ADFFE0:
+ case FF_ADFFE1:
+ cell->type = IdString(stringf("$_DFFE_%c%c%c%c_",
+ (ff_neg & NEG_C) ? 'N' : 'P',
+ (ff_neg & NEG_R) ? 'N' : 'P',
+ (ff_type == FF_ADFFE1) ? '1' : '0',
+ (ff_neg & NEG_E) ? 'N' : 'P'
+ ));
+ cell->setPort(ID::D, sig_d);
+ cell->setPort(ID::Q, sig_q);
+ cell->setPort(ID::C, sig_c);
+ cell->setPort(ID::E, sig_e);
+ cell->setPort(ID::R, sig_r);
+ break;
+ case FF_DFFSR:
+ cell->type = IdString(stringf("$_DFFSR_%c%c%c_",
+ (ff_neg & NEG_C) ? 'N' : 'P',
+ (ff_neg & NEG_S) ? 'N' : 'P',
+ (ff_neg & NEG_R) ? 'N' : 'P'
+ ));
+ cell->setPort(ID::D, sig_d);
+ cell->setPort(ID::Q, sig_q);
+ cell->setPort(ID::C, sig_c);
+ cell->setPort(ID::S, sig_s);
+ cell->setPort(ID::R, sig_r);
+ break;
+ case FF_DFFSRE:
+ cell->type = IdString(stringf("$_DFFSRE_%c%c%c%c_",
+ (ff_neg & NEG_C) ? 'N' : 'P',
+ (ff_neg & NEG_S) ? 'N' : 'P',
+ (ff_neg & NEG_R) ? 'N' : 'P',
+ (ff_neg & NEG_E) ? 'N' : 'P'
+ ));
+ cell->setPort(ID::D, sig_d);
+ cell->setPort(ID::Q, sig_q);
+ cell->setPort(ID::C, sig_c);
+ cell->setPort(ID::E, sig_e);
+ cell->setPort(ID::S, sig_s);
+ cell->setPort(ID::R, sig_r);
+ break;
+ case FF_SDFF0:
+ case FF_SDFF1:
+ cell->type = IdString(stringf("$_SDFF_%c%c%c_",
+ (ff_neg & NEG_C) ? 'N' : 'P',
+ (ff_neg & NEG_R) ? 'N' : 'P',
+ (ff_type == FF_SDFF1) ? '1' : '0'
+ ));
+ cell->setPort(ID::D, sig_d);
+ cell->setPort(ID::Q, sig_q);
+ cell->setPort(ID::C, sig_c);
+ cell->setPort(ID::R, sig_r);
+ break;
+ case FF_SDFFE0:
+ case FF_SDFFE1:
+ cell->type = IdString(stringf("$_SDFFE_%c%c%c%c_",
+ (ff_neg & NEG_C) ? 'N' : 'P',
+ (ff_neg & NEG_R) ? 'N' : 'P',
+ (ff_type == FF_SDFFE1) ? '1' : '0',
+ (ff_neg & NEG_E) ? 'N' : 'P'
+ ));
+ cell->setPort(ID::D, sig_d);
+ cell->setPort(ID::Q, sig_q);
+ cell->setPort(ID::C, sig_c);
+ cell->setPort(ID::E, sig_e);
+ cell->setPort(ID::R, sig_r);
+ break;
+ case FF_SDFFCE0:
+ case FF_SDFFCE1:
+ cell->type = IdString(stringf("$_SDFFCE_%c%c%c%c_",
+ (ff_neg & NEG_C) ? 'N' : 'P',
+ (ff_neg & NEG_R) ? 'N' : 'P',
+ (ff_type == FF_SDFFCE1) ? '1' : '0',
+ (ff_neg & NEG_E) ? 'N' : 'P'
+ ));
+ cell->setPort(ID::D, sig_d);
+ cell->setPort(ID::Q, sig_q);
+ cell->setPort(ID::C, sig_c);
+ cell->setPort(ID::E, sig_e);
+ cell->setPort(ID::R, sig_r);
+ break;
+ case FF_DLATCH:
+ cell->type = IdString(stringf("$_DLATCH_%c_",
+ (ff_neg & NEG_E) ? 'N' : 'P'
+ ));
+ cell->setPort(ID::D, sig_d);
+ cell->setPort(ID::Q, sig_q);
+ cell->setPort(ID::E, sig_e);
+ break;
+ case FF_ADLATCH0:
+ case FF_ADLATCH1:
+ cell->type = IdString(stringf("$_DLATCH_%c%c%c_",
+ (ff_neg & NEG_E) ? 'N' : 'P',
+ (ff_neg & NEG_R) ? 'N' : 'P',
+ (ff_type == FF_ADLATCH1) ? '1' : '0'
+ ));
+ cell->setPort(ID::D, sig_d);
+ cell->setPort(ID::Q, sig_q);
+ cell->setPort(ID::E, sig_e);
+ cell->setPort(ID::R, sig_r);
+ break;
+ case FF_DLATCHSR:
+ cell->type = IdString(stringf("$_DLATCHSR_%c%c%c_",
+ (ff_neg & NEG_E) ? 'N' : 'P',
+ (ff_neg & NEG_S) ? 'N' : 'P',
+ (ff_neg & NEG_R) ? 'N' : 'P'
+ ));
+ cell->setPort(ID::D, sig_d);
+ cell->setPort(ID::Q, sig_q);
+ cell->setPort(ID::E, sig_e);
+ cell->setPort(ID::S, sig_s);
+ cell->setPort(ID::R, sig_r);
+ break;
+ case FF_SR:
+ cell->type = IdString(stringf("$_SR_%c%c_",
+ (ff_neg & NEG_S) ? 'N' : 'P',
+ (ff_neg & NEG_R) ? 'N' : 'P'
+ ));
+ cell->setPort(ID::Q, sig_q);
+ cell->setPort(ID::S, sig_s);
+ cell->setPort(ID::R, sig_r);
+ break;
+ default:
+ log_assert(0);
+ }
+ return;
+
+error:
+ log_error("FF %s.%s (type %s) cannot be legalized: %s\n", log_id(cell->module->name), log_id(cell->name), log_id(cell->type), reason);
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
+ {
+
+ log_header(design, "Executing DFFLEGALIZE pass (convert FFs to types supported by the target).\n");
+
+ for (int i = 0; i < NUM_FFTYPES; i++) {
+ for (int j = 0; j < NUM_NEG; j++)
+ supported_cells_neg[i][j] = 0;
+ supported_cells[i] = 0;
+ }
+ mince = 0;
+ minsrst = 0;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-cell" && argidx + 2 < args.size()) {
+ std::string celltype = args[++argidx];
+ std::string inittype = args[++argidx];
+ enum FfType ff_type[2] = {NUM_FFTYPES, NUM_FFTYPES};
+ char pol_c = 0;
+ char pol_e = 0;
+ char pol_s = 0;
+ char pol_r = 0;
+ char srval = 0;
+ if (celltype.substr(0, 5) == "$_SR_" && celltype.size() == 8 && celltype[7] == '_') {
+ ff_type[0] = FF_SR;
+ pol_s = celltype[5];
+ pol_r = celltype[6];
+ } else if (celltype.substr(0, 6) == "$_DFF_" && celltype.size() == 8 && celltype[7] == '_') {
+ ff_type[0] = FF_DFF;
+ pol_c = celltype[6];
+ } else if (celltype.substr(0, 7) == "$_DFFE_" && celltype.size() == 10 && celltype[9] == '_') {
+ ff_type[0] = FF_DFFE;
+ pol_c = celltype[7];
+ pol_e = celltype[8];
+ } else if (celltype.substr(0, 6) == "$_DFF_" && celltype.size() == 10 && celltype[9] == '_') {
+ ff_type[0] = FF_ADFF0;
+ ff_type[1] = FF_ADFF1;
+ pol_c = celltype[6];
+ pol_r = celltype[7];
+ srval = celltype[8];
+ } else if (celltype.substr(0, 7) == "$_DFFE_" && celltype.size() == 12 && celltype[11] == '_') {
+ ff_type[0] = FF_ADFFE0;
+ ff_type[1] = FF_ADFFE1;
+ pol_c = celltype[7];
+ pol_r = celltype[8];
+ srval = celltype[9];
+ pol_e = celltype[10];
+ } else if (celltype.substr(0, 8) == "$_DFFSR_" && celltype.size() == 12 && celltype[11] == '_') {
+ ff_type[0] = FF_DFFSR;
+ pol_c = celltype[8];
+ pol_s = celltype[9];
+ pol_r = celltype[10];
+ } else if (celltype.substr(0, 9) == "$_DFFSRE_" && celltype.size() == 14 && celltype[13] == '_') {
+ ff_type[0] = FF_DFFSRE;
+ pol_c = celltype[9];
+ pol_s = celltype[10];
+ pol_r = celltype[11];
+ pol_e = celltype[12];
+ } else if (celltype.substr(0, 7) == "$_SDFF_" && celltype.size() == 11 && celltype[10] == '_') {
+ ff_type[0] = FF_SDFF0;
+ ff_type[1] = FF_SDFF1;
+ pol_c = celltype[7];
+ pol_r = celltype[8];
+ srval = celltype[9];
+ } else if (celltype.substr(0, 8) == "$_SDFFE_" && celltype.size() == 13 && celltype[12] == '_') {
+ ff_type[0] = FF_SDFFE0;
+ ff_type[1] = FF_SDFFE1;
+ pol_c = celltype[8];
+ pol_r = celltype[9];
+ srval = celltype[10];
+ pol_e = celltype[11];
+ } else if (celltype.substr(0, 9) == "$_SDFFCE_" && celltype.size() == 14 && celltype[13] == '_') {
+ ff_type[0] = FF_SDFFCE0;
+ ff_type[1] = FF_SDFFCE1;
+ pol_c = celltype[9];
+ pol_r = celltype[10];
+ srval = celltype[11];
+ pol_e = celltype[12];
+ } else if (celltype.substr(0, 9) == "$_DLATCH_" && celltype.size() == 11 && celltype[10] == '_') {
+ ff_type[0] = FF_DLATCH;
+ pol_e = celltype[9];
+ } else if (celltype.substr(0, 9) == "$_DLATCH_" && celltype.size() == 13 && celltype[12] == '_') {
+ ff_type[0] = FF_ADLATCH0;
+ ff_type[1] = FF_ADLATCH1;
+ pol_e = celltype[9];
+ pol_r = celltype[10];
+ srval = celltype[11];
+ } else if (celltype.substr(0, 11) == "$_DLATCHSR_" && celltype.size() == 15 && celltype[14] == '_') {
+ ff_type[0] = FF_DLATCHSR;
+ pol_e = celltype[11];
+ pol_s = celltype[12];
+ pol_r = celltype[13];
+ } else {
+unrecognized:
+ log_error("unrecognized cell type %s.\n", celltype.c_str());
+ }
+ int mask = 0;
+ int match = 0;
+ for (auto pair : {
+ std::make_pair(pol_c, NEG_C),
+ std::make_pair(pol_e, NEG_E),
+ std::make_pair(pol_s, NEG_S),
+ std::make_pair(pol_r, NEG_R),
+ }) {
+ if (pair.first == 'N') {
+ mask |= pair.second;
+ match |= pair.second;
+ } else if (pair.first == 'P' || pair.first == 0) {
+ mask |= pair.second;
+ } else if (pair.first != '?') {
+ goto unrecognized;
+ }
+ }
+ if (srval == '0') {
+ ff_type[1] = NUM_FFTYPES;
+ } else if (srval == '1') {
+ ff_type[0] = NUM_FFTYPES;
+ } else if (srval != 0 && srval != '?') {
+ goto unrecognized;
+ }
+ for (int i = 0; i < 2; i++) {
+ if (ff_type[i] == NUM_FFTYPES)
+ continue;
+ int initmask;
+ if (inittype == "x") {
+ initmask = INIT_X;
+ } else if (inittype == "0") {
+ initmask = INIT_X | INIT_0;
+ } else if (inittype == "1") {
+ initmask = INIT_X | INIT_1;
+ } else if (inittype == "r") {
+ if (srval == 0)
+ log_error("init type r not valid for cell type %s.\n", celltype.c_str());
+ if (i == 0)
+ initmask = INIT_X | INIT_0;
+ else
+ initmask = INIT_X | INIT_1;
+ } else if (inittype == "01") {
+ initmask = INIT_X | INIT_0 | INIT_1;
+ } else {
+ log_error("unrecognized init type %s for cell type %s.\n", inittype.c_str(), celltype.c_str());
+ }
+ for (int neg = 0; neg < NUM_NEG; neg++)
+ if ((neg & mask) == match)
+ supported_cells_neg[ff_type[i]][neg] |= initmask;
+ supported_cells[ff_type[i]] |= initmask;
+ }
+ continue;
+ } else if (args[argidx] == "-mince" && argidx + 1 < args.size()) {
+ mince = atoi(args[++argidx].c_str());
+ continue;
+ } else if (args[argidx] == "-minsrst" && argidx + 1 < args.size()) {
+ minsrst = atoi(args[++argidx].c_str());
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+ supported_dffsr = supported_cells[FF_DFFSR] | supported_cells[FF_DFFSRE];
+ supported_adff0 = supported_cells[FF_ADFF0] | supported_cells[FF_ADFFE0] | supported_dffsr;
+ supported_adff1 = supported_cells[FF_ADFF1] | supported_cells[FF_ADFFE1] | supported_dffsr;
+ supported_sdff0 = supported_cells[FF_SDFF0] | supported_cells[FF_SDFFE0] | supported_cells[FF_SDFFCE0];
+ supported_sdff1 = supported_cells[FF_SDFF1] | supported_cells[FF_SDFFE1] | supported_cells[FF_SDFFCE1];
+ supported_dff = supported_cells[FF_DFF] | supported_cells[FF_DFFE] | supported_dffsr | supported_adff0 | supported_adff1 | supported_sdff0 | supported_sdff1;
+ supported_sr = supported_dffsr | supported_cells[FF_DLATCHSR] | supported_cells[FF_SR] | supported_cells[FF_ADLATCH0] | flip_initmask(supported_cells[FF_ADLATCH1]);
+ supported_dlatch = supported_cells[FF_DLATCH] | supported_cells[FF_ADLATCH0] | supported_cells[FF_ADLATCH1] | supported_cells[FF_DLATCHSR];
+
+ for (auto module : design->selected_modules())
+ {
+ sigmap.set(module);
+ initvals.set(&sigmap, module);
+
+ if (mince || minsrst) {
+ ce_used.clear();
+ srst_used.clear();
+
+ for (auto cell : module->cells()) {
+ if (!RTLIL::builtin_ff_cell_types().count(cell->type))
+ continue;
+
+ if (cell->hasPort(ID::C) && cell->hasPort(ID::E)) {
+ SigSpec sig = cell->getPort(ID::E);
+ // Do not count const enable signals.
+ if (GetSize(sig) == 1 && sig[0].wire)
+ ce_used[sig[0]]++;
+ }
+ if (cell->type.str().substr(0, 6) == "$_SDFF") {
+ SigSpec sig = cell->getPort(ID::R);
+ // Do not count const srst signals.
+ if (GetSize(sig) == 1 && sig[0].wire)
+ srst_used[sig[0]]++;
+ }
+ }
+ }
+
+ // First gather FF cells, then iterate over them later.
+ // We may need to split an FF into several cells.
+ std::vector<Cell *> ff_cells;
+
+ for (auto cell : module->selected_cells())
+ {
+ // Early exit for non-FFs.
+ if (!RTLIL::builtin_ff_cell_types().count(cell->type))
+ continue;
+
+ ff_cells.push_back(cell);
+ }
+
+ for (auto cell: ff_cells)
+ handle_ff(cell);
+ }
+
+ sigmap.clear();
+ initvals.clear();
+ ce_used.clear();
+ srst_used.clear();
+ }
+} DffLegalizePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc
index aa344cf8a..78a6f1c0d 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -115,7 +115,7 @@ static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name,
return false;
}
-static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool prepare_mode)
+static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval)
{
LibertyAst *best_cell = nullptr;
std::map<std::string, char> best_cell_ports;
@@ -222,21 +222,12 @@ static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has
if (best_cell != nullptr) {
log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n",
best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str());
- if (prepare_mode) {
- cell_mappings[cell_type].cell_name = cell_type;
- cell_mappings[cell_type].ports["C"] = 'C';
- if (has_reset)
- cell_mappings[cell_type].ports["R"] = 'R';
- cell_mappings[cell_type].ports["D"] = 'D';
- cell_mappings[cell_type].ports["Q"] = 'Q';
- } else {
- cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]);
- cell_mappings[cell_type].ports = best_cell_ports;
- }
+ cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]);
+ cell_mappings[cell_type].ports = best_cell_ports;
}
}
-static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool setpol, bool clrpol, bool prepare_mode)
+static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool setpol, bool clrpol)
{
LibertyAst *best_cell = nullptr;
std::map<std::string, char> best_cell_ports;
@@ -339,141 +330,12 @@ static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool
if (best_cell != nullptr) {
log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n",
best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str());
- if (prepare_mode) {
- cell_mappings[cell_type].cell_name = cell_type;
- cell_mappings[cell_type].ports["C"] = 'C';
- cell_mappings[cell_type].ports["S"] = 'S';
- cell_mappings[cell_type].ports["R"] = 'R';
- cell_mappings[cell_type].ports["D"] = 'D';
- cell_mappings[cell_type].ports["Q"] = 'Q';
- } else {
- cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]);
- cell_mappings[cell_type].ports = best_cell_ports;
- }
+ cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]);
+ cell_mappings[cell_type].ports = best_cell_ports;
}
}
-static bool expand_cellmap_worker(std::string from, std::string to, std::string inv)
-{
- if (cell_mappings.count(to) > 0)
- return false;
-
- log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str());
- cell_mappings[to].cell_name = cell_mappings[from].cell_name;
- cell_mappings[to].ports = cell_mappings[from].ports;
-
- for (auto &it : cell_mappings[to].ports) {
- char cmp_ch = it.second;
- if ('a' <= cmp_ch && cmp_ch <= 'z')
- cmp_ch -= 'a' - 'A';
- if (inv.find(cmp_ch) == std::string::npos)
- continue;
- if ('a' <= it.second && it.second <= 'z')
- it.second -= 'a' - 'A';
- else if ('A' <= it.second && it.second <= 'Z')
- it.second += 'a' - 'A';
- }
- return true;
-}
-
-static bool expand_cellmap(std::string pattern, std::string inv)
-{
- std::vector<std::pair<std::string, std::string>> from_to_list;
- bool return_status = false;
-
- for (auto &it : cell_mappings) {
- std::string from = it.first.str(), to = it.first.str();
- if (from.size() != pattern.size())
- continue;
- for (size_t i = 0; i < from.size(); i++) {
- if (pattern[i] == '*') {
- to[i] = from[i] == 'P' ? 'N' :
- from[i] == 'N' ? 'P' :
- from[i] == '1' ? '0' :
- from[i] == '0' ? '1' : '*';
- } else
- if (pattern[i] != '?' && pattern[i] != from[i])
- goto pattern_failed;
- }
- from_to_list.push_back(std::pair<std::string, std::string>(from, to));
- pattern_failed:;
- }
-
- for (auto &it : from_to_list)
- return_status = return_status || expand_cellmap_worker(it.first, it.second, inv);
- return return_status;
-}
-
-static void map_sr_to_arst(IdString from, IdString to)
-{
- if (!cell_mappings.count(from) || cell_mappings.count(to) > 0)
- return;
-
- char from_clk_pol YS_ATTRIBUTE(unused) = from[8];
- char from_set_pol = from[9];
- char from_clr_pol = from[10];
- char to_clk_pol YS_ATTRIBUTE(unused) = to[6];
- char to_rst_pol YS_ATTRIBUTE(unused) = to[7];
- char to_rst_val = to[8];
-
- log_assert(from_clk_pol == to_clk_pol);
- log_assert(to_rst_pol == from_set_pol && to_rst_pol == from_clr_pol);
-
- log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str());
- cell_mappings[to].cell_name = cell_mappings[from].cell_name;
- cell_mappings[to].ports = cell_mappings[from].ports;
-
- for (auto &it : cell_mappings[to].ports)
- {
- bool is_set_pin = it.second == 'S' || it.second == 's';
- bool is_clr_pin = it.second == 'R' || it.second == 'r';
-
- if (!is_set_pin && !is_clr_pin)
- continue;
-
- if ((to_rst_val == '0' && is_set_pin) || (to_rst_val == '1' && is_clr_pin))
- {
- // this is the unused set/clr pin -- deactivate it
- if (is_set_pin)
- it.second = (from_set_pol == 'P') == (it.second == 'S') ? '0' : '1';
- else
- it.second = (from_clr_pol == 'P') == (it.second == 'R') ? '0' : '1';
- }
- else
- {
- // this is the used set/clr pin -- rename it to 'reset'
- if (it.second == 'S')
- it.second = 'R';
- if (it.second == 's')
- it.second = 'r';
- }
- }
-}
-
-static void map_adff_to_dff(IdString from, IdString to)
-{
- if (!cell_mappings.count(from) || cell_mappings.count(to) > 0)
- return;
-
- char from_clk_pol YS_ATTRIBUTE(unused) = from[6];
- char from_rst_pol = from[7];
- char to_clk_pol YS_ATTRIBUTE(unused) = to[6];
-
- log_assert(from_clk_pol == to_clk_pol);
-
- log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str());
- cell_mappings[to].cell_name = cell_mappings[from].cell_name;
- cell_mappings[to].ports = cell_mappings[from].ports;
-
- for (auto &it : cell_mappings[to].ports) {
- if (it.second == 'S' || it.second == 'R')
- it.second = from_rst_pol == 'P' ? '0' : '1';
- if (it.second == 's' || it.second == 'r')
- it.second = from_rst_pol == 'P' ? '1' : '0';
- }
-}
-
-static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare_mode)
+static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module)
{
log("Mapping DFF cells in module `%s':\n", module->name.c_str());
@@ -499,7 +361,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare
module->remove(cell);
cell_mapping &cm = cell_mappings[cell_type];
- RTLIL::Cell *new_cell = module->addCell(cell_name, prepare_mode ? cm.cell_name : cm.cell_name);
+ RTLIL::Cell *new_cell = module->addCell(cell_name, cm.cell_name);
new_cell->set_src_attribute(src);
@@ -549,10 +411,10 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare
struct DfflibmapPass : public Pass {
DfflibmapPass() : Pass("dfflibmap", "technology mapping of flip-flops") { }
- void help() YS_OVERRIDE
+ void help() override
{
log("\n");
- log(" dfflibmap [-prepare] -liberty <file> [selection]\n");
+ log(" dfflibmap [-prepare] [-map-only] [-info] -liberty <file> [selection]\n");
log("\n");
log("Map internal flip-flop cells to the flip-flop cells in the technology\n");
log("library specified in the given liberty file.\n");
@@ -562,15 +424,27 @@ struct DfflibmapPass : public Pass {
log("\n");
log("When called with -prepare, this command will convert the internal FF cells\n");
log("to the internal cell types that best match the cells found in the given\n");
- log("liberty file.\n");
+ log("liberty file, but won't actually map them to the target cells.\n");
+ log("\n");
+ log("When called with -map-only, this command will only map internal cell\n");
+ log("types that are already of exactly the right type to match the target\n");
+ log("cells, leaving remaining internal cells untouched.\n");
+ log("\n");
+ log("When called with -info, this command will only print the target cell\n");
+ log("list, along with their associated internal cell types, and the arguments");
+ log("that would be passed to the dfflegalize pass. The design will not be\n");
+ log("changed.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
+ log_push();
std::string liberty_file;
bool prepare_mode = false;
+ bool map_only_mode = false;
+ bool info_mode = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -585,10 +459,28 @@ struct DfflibmapPass : public Pass {
prepare_mode = true;
continue;
}
+ if (arg == "-map-only") {
+ map_only_mode = true;
+ continue;
+ }
+ if (arg == "-info") {
+ info_mode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
+ int modes = 0;
+ if (prepare_mode)
+ modes++;
+ if (map_only_mode)
+ modes++;
+ if (info_mode)
+ modes++;
+ if (modes > 1)
+ log_cmd_error("Only one of -prepare, -map-only, or -info options should be given!\n");
+
if (liberty_file.empty())
log_cmd_error("Missing `-liberty liberty_file' option!\n");
@@ -599,74 +491,49 @@ struct DfflibmapPass : public Pass {
LibertyParser libparser(f);
f.close();
- find_cell(libparser.ast, ID($_DFF_N_), false, false, false, false, prepare_mode);
- find_cell(libparser.ast, ID($_DFF_P_), true, false, false, false, prepare_mode);
-
- find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false, prepare_mode);
- find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true, prepare_mode);
- find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false, prepare_mode);
- find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true, prepare_mode);
- find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false, prepare_mode);
- find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true, prepare_mode);
- find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false, prepare_mode);
- find_cell(libparser.ast, ID($_DFF_PP1_), true, true, true, true, prepare_mode);
-
- find_cell_sr(libparser.ast, ID($_DFFSR_NNN_), false, false, false, prepare_mode);
- find_cell_sr(libparser.ast, ID($_DFFSR_NNP_), false, false, true, prepare_mode);
- find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false, prepare_mode);
- find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true, prepare_mode);
- find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false, prepare_mode);
- find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true, prepare_mode);
- find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false, prepare_mode);
- find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true, prepare_mode);
-
- // try to implement as many cells as possible just by inverting
- // the SET and RESET pins. If necessary, implement cell types
- // by inverting both D and Q. Only invert clock pins if there
- // is no other way of implementing the cell.
- while (1)
- {
- if (expand_cellmap("$_DFF_?*?_", "R") ||
- expand_cellmap("$_DFFSR_?*?_", "S") ||
- expand_cellmap("$_DFFSR_??*_", "R"))
- continue;
-
- if (expand_cellmap("$_DFF_??*_", "DQ"))
- continue;
-
- if (expand_cellmap("$_DFF_*_", "C") ||
- expand_cellmap("$_DFF_*??_", "C") ||
- expand_cellmap("$_DFFSR_*??_", "C"))
- continue;
-
- break;
- }
-
- map_sr_to_arst(ID($_DFFSR_NNN_), ID($_DFF_NN0_));
- map_sr_to_arst(ID($_DFFSR_NNN_), ID($_DFF_NN1_));
- map_sr_to_arst(ID($_DFFSR_NPP_), ID($_DFF_NP0_));
- map_sr_to_arst(ID($_DFFSR_NPP_), ID($_DFF_NP1_));
- map_sr_to_arst(ID($_DFFSR_PNN_), ID($_DFF_PN0_));
- map_sr_to_arst(ID($_DFFSR_PNN_), ID($_DFF_PN1_));
- map_sr_to_arst(ID($_DFFSR_PPP_), ID($_DFF_PP0_));
- map_sr_to_arst(ID($_DFFSR_PPP_), ID($_DFF_PP1_));
-
- map_adff_to_dff(ID($_DFF_NN0_), ID($_DFF_N_));
- map_adff_to_dff(ID($_DFF_NN1_), ID($_DFF_N_));
- map_adff_to_dff(ID($_DFF_NP0_), ID($_DFF_N_));
- map_adff_to_dff(ID($_DFF_NP1_), ID($_DFF_N_));
- map_adff_to_dff(ID($_DFF_PN0_), ID($_DFF_P_));
- map_adff_to_dff(ID($_DFF_PN1_), ID($_DFF_P_));
- map_adff_to_dff(ID($_DFF_PP0_), ID($_DFF_P_));
- map_adff_to_dff(ID($_DFF_PP1_), ID($_DFF_P_));
+ find_cell(libparser.ast, ID($_DFF_N_), false, false, false, false);
+ find_cell(libparser.ast, ID($_DFF_P_), true, false, false, false);
+
+ find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false);
+ find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true);
+ find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false);
+ find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true);
+ find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false);
+ find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true);
+ find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false);
+ find_cell(libparser.ast, ID($_DFF_PP1_), true, true, true, true);
+
+ find_cell_sr(libparser.ast, ID($_DFFSR_NNN_), false, false, false);
+ find_cell_sr(libparser.ast, ID($_DFFSR_NNP_), false, false, true);
+ find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false);
+ find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true);
+ find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false);
+ find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true);
+ find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false);
+ find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true);
log(" final dff cell mappings:\n");
logmap_all();
- for (auto module : design->selected_modules())
- if (!module->get_blackbox_attribute())
- dfflibmap(design, module, prepare_mode);
+ if (!map_only_mode) {
+ std::string dfflegalize_cmd = "dfflegalize";
+ for (auto it : cell_mappings)
+ dfflegalize_cmd += stringf(" -cell %s 01", it.first.c_str());
+ dfflegalize_cmd += " t:$_DFF* t:$_SDFF*";
+ if (info_mode) {
+ log("dfflegalize command line: %s\n", dfflegalize_cmd.c_str());
+ } else {
+ Pass::call(design, dfflegalize_cmd);
+ }
+ }
+
+ if (!prepare_mode && !info_mode) {
+ for (auto module : design->selected_modules())
+ if (!module->get_blackbox_attribute())
+ dfflibmap(design, module);
+ }
+ log_pop();
cell_mappings.clear();
}
} DfflibmapPass;
diff --git a/passes/techmap/dffunmap.cc b/passes/techmap/dffunmap.cc
new file mode 100644
index 000000000..fb107ff75
--- /dev/null
+++ b/passes/techmap/dffunmap.cc
@@ -0,0 +1,107 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2020 Marcelina Kościelnicka <mwk@0x04.net>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "kernel/ff.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct DffunmapPass : public Pass {
+ DffunmapPass() : Pass("dffunmap", "unmap clock enable and synchronous reset from FFs") { }
+ void help() override
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" dffunmap [options] [selection]\n");
+ log("\n");
+ log("This pass transforms FF types with clock enable and/or synchronous reset into\n");
+ log("their base type (with neither clock enable nor sync reset) by emulating the clock\n");
+ log("enable and synchronous reset with multiplexers on the cell input.\n");
+ log("\n");
+ log(" -ce-only\n");
+ log(" unmap only clock enables, leave synchronous resets alone.\n");
+ log("\n");
+ log(" -srst-only\n");
+ log(" unmap only synchronous resets, leave clock enables alone.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
+ {
+ log_header(design, "Executing DFFUNMAP pass (unmap clock enable and synchronous reset from FFs).\n");
+
+ bool ce_only = false;
+ bool srst_only = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-ce-only") {
+ ce_only = true;
+ continue;
+ }
+ if (args[argidx] == "-srst-only") {
+ srst_only = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (ce_only && srst_only)
+ log_cmd_error("Options -ce-only and -srst-only are mutually exclusive!\n");
+
+ for (auto mod : design->selected_modules())
+ {
+ SigMap sigmap(mod);
+ FfInitVals initvals(&sigmap, mod);
+
+ for (auto cell : mod->selected_cells())
+ {
+ if (!RTLIL::builtin_ff_cell_types().count(cell->type))
+ continue;
+
+ FfData ff(&initvals, cell);
+ IdString name = cell->name;
+
+ if (!ff.has_clk)
+ continue;
+
+ if (ce_only) {
+ if (!ff.has_en)
+ continue;
+ ff.unmap_ce(mod);
+ } else if (srst_only) {
+ if (!ff.has_srst)
+ continue;
+ ff.unmap_srst(mod);
+ } else {
+ if (!ff.has_en && !ff.has_srst)
+ continue;
+ ff.unmap_ce_srst(mod);
+ }
+
+ mod->remove(cell);
+ ff.emit(mod, name);
+ }
+ }
+ }
+} DffunmapPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc
index f29044790..f5966fac0 100644
--- a/passes/techmap/extract.cc
+++ b/passes/techmap/extract.cc
@@ -345,7 +345,7 @@ bool compareSortNeedleList(RTLIL::Module *left, RTLIL::Module *right)
struct ExtractPass : public Pass {
ExtractPass() : Pass("extract", "find subcircuits and replace them with cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -354,7 +354,7 @@ struct ExtractPass : public Pass {
log("\n");
log("This pass looks for subcircuits that are isomorphic to any of the modules\n");
log("in the given map file and replaces them with instances of this modules. The\n");
- log("map file can be a Verilog source file (*.v) or an ilang file (*.il).\n");
+ log("map file can be a Verilog source file (*.v) or an RTLIL source file (*.il).\n");
log("\n");
log(" -map <map_file>\n");
log(" use the modules in this file as reference. This option can be used\n");
@@ -409,7 +409,7 @@ struct ExtractPass : public Pass {
log("the following options are to be used instead of the -map option.\n");
log("\n");
log(" -mine <out_file>\n");
- log(" mine for frequent subcircuits and write them to the given ilang file\n");
+ log(" mine for frequent subcircuits and write them to the given RTLIL file\n");
log("\n");
log(" -mine_cells_span <min> <max>\n");
log(" only mine for subcircuits with the specified number of cells\n");
@@ -433,7 +433,7 @@ struct ExtractPass : public Pass {
log("See 'help techmap' for a pass that does the opposite thing.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing EXTRACT pass (map subcircuits to cells).\n");
log_push();
@@ -578,7 +578,7 @@ struct ExtractPass : public Pass {
}
if (map_filenames.empty() && mine_outfile.empty())
- log_cmd_error("Missing option -map <verilog_or_ilang_file> or -mine <output_ilang_file>.\n");
+ log_cmd_error("Missing option -map <verilog_or_rtlil_file> or -mine <output_rtlil_file>.\n");
RTLIL::Design *map = nullptr;
@@ -606,7 +606,7 @@ struct ExtractPass : public Pass {
delete map;
log_cmd_error("Can't open map file `%s'.\n", filename.c_str());
}
- Frontend::frontend_call(map, &f, filename, (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0 ? "ilang" : "verilog"));
+ Frontend::frontend_call(map, &f, filename, (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0 ? "rtlil" : "verilog"));
f.close();
if (filename.size() <= 3 || filename.compare(filename.size()-3, std::string::npos, ".il") != 0) {
@@ -744,7 +744,7 @@ struct ExtractPass : public Pass {
f.open(mine_outfile.c_str(), std::ofstream::trunc);
if (f.fail())
log_error("Can't open output file `%s'.\n", mine_outfile.c_str());
- Backend::backend_call(map, &f, mine_outfile, "ilang");
+ Backend::backend_call(map, &f, mine_outfile, "rtlil");
f.close();
}
diff --git a/passes/techmap/extract_counter.cc b/passes/techmap/extract_counter.cc
index 68b338143..56b2ea584 100644
--- a/passes/techmap/extract_counter.cc
+++ b/passes/techmap/extract_counter.cc
@@ -760,7 +760,7 @@ void counter_worker(
struct ExtractCounterPass : public Pass {
ExtractCounterPass() : Pass("extract_counter", "Extract GreenPak4 counter cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -788,18 +788,18 @@ struct ExtractCounterPass : public Pass {
log("\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing EXTRACT_COUNTER pass (find counters in netlist).\n");
pool<RTLIL::IdString> _parallel_cells;
CounterExtractionSettings settings
{
- .parallel_cells = _parallel_cells,
- .maxwidth = 64,
- .minwidth = 2,
- .allow_arst = true,
- .allowed_dirs = 0,
+ _parallel_cells, // parallel_cells
+ 64, // maxwidth
+ 2, // minwidth
+ true, // allow_arst
+ 0, // allowed_dirs
};
size_t argidx;
diff --git a/passes/techmap/extract_fa.cc b/passes/techmap/extract_fa.cc
index 9023d8687..3fcff01c3 100644
--- a/passes/techmap/extract_fa.cc
+++ b/passes/techmap/extract_fa.cc
@@ -539,7 +539,7 @@ struct ExtractFaWorker
struct ExtractFaPass : public Pass {
ExtractFaPass() : Pass("extract_fa", "find and extract full/half adders") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -561,7 +561,7 @@ struct ExtractFaPass : public Pass {
log(" Verbose output\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
ExtractFaConfig config;
diff --git a/passes/techmap/extract_reduce.cc b/passes/techmap/extract_reduce.cc
index 2d63e413f..07b4200cc 100644
--- a/passes/techmap/extract_reduce.cc
+++ b/passes/techmap/extract_reduce.cc
@@ -34,7 +34,7 @@ struct ExtractReducePass : public Pass
ExtractReducePass() : Pass("extract_reduce", "converts gate chains into $reduce_* cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -63,7 +63,7 @@ struct ExtractReducePass : public Pass
(cell->type == ID($_XOR_) && gt == GateType::Xor);
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing EXTRACT_REDUCE pass.\n");
log_push();
diff --git a/passes/techmap/extractinv.cc b/passes/techmap/extractinv.cc
index 269fe5c6c..11463380c 100644
--- a/passes/techmap/extractinv.cc
+++ b/passes/techmap/extractinv.cc
@@ -2,7 +2,7 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- * Copyright (C) 2019 Marcin Kościelnicki <mwk@0x04.net>
+ * Copyright (C) 2019 Marcelina Kościelnicka <mwk@0x04.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -35,7 +35,7 @@ void split_portname_pair(std::string &port1, std::string &port2)
struct ExtractinvPass : public Pass {
ExtractinvPass() : Pass("extractinv", "extract explicit inverter cells for invertible cell pins") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -57,7 +57,7 @@ struct ExtractinvPass : public Pass {
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing EXTRACTINV pass (extracting pin inverters).\n");
diff --git a/passes/techmap/flatten.cc b/passes/techmap/flatten.cc
index a03226f9f..08978f446 100644
--- a/passes/techmap/flatten.cc
+++ b/passes/techmap/flatten.cc
@@ -152,15 +152,14 @@ struct FlattenWorker
// Attach port connections of the flattened cell
- SigMap tpl_sigmap(tpl);
pool<SigBit> tpl_driven;
for (auto tpl_cell : tpl->cells())
for (auto &tpl_conn : tpl_cell->connections())
if (tpl_cell->output(tpl_conn.first))
- for (auto bit : tpl_sigmap(tpl_conn.second))
+ for (auto bit : tpl_conn.second)
tpl_driven.insert(bit);
for (auto &tpl_conn : tpl->connections())
- for (auto bit : tpl_sigmap(tpl_conn.first))
+ for (auto bit : tpl_conn.first)
tpl_driven.insert(bit);
SigMap sigmap(module);
@@ -190,7 +189,7 @@ struct FlattenWorker
} else {
SigSpec sig_tpl = tpl_wire, sig_mod = port_it.second;
for (int i = 0; i < GetSize(sig_tpl) && i < GetSize(sig_mod); i++) {
- if (tpl_driven.count(tpl_sigmap(sig_tpl[i]))) {
+ if (tpl_driven.count(sig_tpl[i])) {
new_conn.first.append(sig_mod[i]);
new_conn.second.append(sig_tpl[i]);
} else {
@@ -253,7 +252,7 @@ struct FlattenWorker
struct FlattenPass : public Pass {
FlattenPass() : Pass("flatten", "flatten design") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -270,7 +269,7 @@ struct FlattenPass : public Pass {
log(" Ignore the 'whitebox' attribute on cell implementations.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing FLATTEN pass (flatten design).\n");
log_push();
diff --git a/passes/techmap/flowmap.cc b/passes/techmap/flowmap.cc
index 72947237b..dfdbe6b88 100644
--- a/passes/techmap/flowmap.cc
+++ b/passes/techmap/flowmap.cc
@@ -1470,7 +1470,7 @@ static void split(std::vector<std::string> &tokens, const std::string &text, cha
struct FlowmapPass : public Pass {
FlowmapPass() : Pass("flowmap", "pack LUTs with FlowMap") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1511,7 +1511,7 @@ struct FlowmapPass : public Pass {
log(" explain decisions performed during depth relaxation.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
int order = 3;
int minlut = 1;
diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc
index 5aeb5ea79..b808a8d8e 100644
--- a/passes/techmap/hilomap.cc
+++ b/passes/techmap/hilomap.cc
@@ -55,7 +55,7 @@ void hilomap_worker(RTLIL::SigSpec &sig)
struct HilomapPass : public Pass {
HilomapPass() : Pass("hilomap", "technology mapping of constant hi- and/or lo-drivers") { }
- void help() YS_OVERRIDE
+ void help() override
{
log("\n");
log(" hilomap [options] [selection]\n");
@@ -74,7 +74,7 @@ struct HilomapPass : public Pass {
log(" each constant bit.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing HILOMAP pass (mapping to constant drivers).\n");
diff --git a/passes/techmap/insbuf.cc b/passes/techmap/insbuf.cc
index 0686c0f2b..a3b5b698d 100644
--- a/passes/techmap/insbuf.cc
+++ b/passes/techmap/insbuf.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct InsbufPass : public Pass {
InsbufPass() : Pass("insbuf", "insert buffer cells for connected wires") { }
- void help() YS_OVERRIDE
+ void help() override
{
log("\n");
log(" insbuf [options] [selection]\n");
@@ -37,7 +37,7 @@ struct InsbufPass : public Pass {
log(" call to \"clean\" will remove all $_BUF_ in the design.)\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing INSBUF pass (insert buffer cells for connected wires).\n");
diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc
index a18d02652..e8530a034 100644
--- a/passes/techmap/iopadmap.cc
+++ b/passes/techmap/iopadmap.cc
@@ -34,7 +34,7 @@ void split_portname_pair(std::string &port1, std::string &port2)
struct IopadmapPass : public Pass {
IopadmapPass() : Pass("iopadmap", "technology mapping of i/o pads (or buffers)") { }
- void help() YS_OVERRIDE
+ void help() override
{
log("\n");
log(" iopadmap [options] [selection]\n");
@@ -97,7 +97,7 @@ struct IopadmapPass : public Pass {
modules_processed.insert(module);
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing IOPADMAP pass (mapping inputs/outputs to IO-PAD cells).\n");
diff --git a/passes/techmap/lut2mux.cc b/passes/techmap/lut2mux.cc
index 703bf6ff6..f56eff3e5 100644
--- a/passes/techmap/lut2mux.cc
+++ b/passes/techmap/lut2mux.cc
@@ -56,7 +56,7 @@ int lut2mux(Cell *cell)
struct Lut2muxPass : public Pass {
Lut2muxPass() : Pass("lut2mux", "convert $lut to $_MUX_") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -65,7 +65,7 @@ struct Lut2muxPass : public Pass {
log("This pass converts $lut cells to $_MUX_ gates.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing LUT2MUX pass (convert $lut to $_MUX_).\n");
diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc
index 3bb929009..43f2d97f5 100644
--- a/passes/techmap/maccmap.cc
+++ b/passes/techmap/maccmap.cc
@@ -365,7 +365,7 @@ PRIVATE_NAMESPACE_BEGIN
struct MaccmapPass : public Pass {
MaccmapPass() : Pass("maccmap", "mapping macc cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -375,7 +375,7 @@ struct MaccmapPass : public Pass {
log("is used then the $macc cell is mapped to $add, $sub, etc. cells instead.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool unmap_mode = false;
diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc
index bd049d86d..24109b579 100644
--- a/passes/techmap/muxcover.cc
+++ b/passes/techmap/muxcover.cc
@@ -623,7 +623,7 @@ struct MuxcoverWorker
struct MuxcoverPass : public Pass {
MuxcoverPass() : Pass("muxcover", "cover trees of MUX cells with wider MUXes") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -656,7 +656,7 @@ struct MuxcoverPass : public Pass {
log(" than <N> different signals.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing MUXCOVER pass (mapping to wider MUXes).\n");
diff --git a/passes/techmap/nlutmap.cc b/passes/techmap/nlutmap.cc
index 798d82248..e1ebfcad8 100644
--- a/passes/techmap/nlutmap.cc
+++ b/passes/techmap/nlutmap.cc
@@ -129,7 +129,7 @@ struct NlutmapWorker
struct NlutmapPass : public Pass {
NlutmapPass() : Pass("nlutmap", "map to LUTs of different sizes") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -149,7 +149,7 @@ struct NlutmapPass : public Pass {
log("to generic logic gates ($_AND_, etc.).\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
NlutmapConfig config;
diff --git a/passes/techmap/pmuxtree.cc b/passes/techmap/pmuxtree.cc
index 2810b7f2d..b937d3fb0 100644
--- a/passes/techmap/pmuxtree.cc
+++ b/passes/techmap/pmuxtree.cc
@@ -67,7 +67,7 @@ static SigSpec recursive_mux_generator(Module *module, const SigSpec &sig_data,
struct PmuxtreePass : public Pass {
PmuxtreePass() : Pass("pmuxtree", "transform $pmux cells to trees of $mux cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -76,7 +76,7 @@ struct PmuxtreePass : public Pass {
log("This pass transforms $pmux cells to trees of $mux cells.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing PMUXTREE pass.\n");
diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc
index d7a381e0a..b971068f7 100644
--- a/passes/techmap/shregmap.cc
+++ b/passes/techmap/shregmap.cc
@@ -19,6 +19,7 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
+#include "kernel/ffinit.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -100,9 +101,8 @@ struct ShregmapWorker
int dff_count, shreg_count;
pool<Cell*> remove_cells;
- pool<SigBit> remove_init;
- dict<SigBit, bool> sigbit_init;
+ FfInitVals initvals;
dict<SigBit, Cell*> sigbit_chain_next;
dict<SigBit, Cell*> sigbit_chain_prev;
pool<SigBit> sigbit_with_non_chain_users;
@@ -116,16 +116,6 @@ struct ShregmapWorker
for (auto bit : sigmap(wire))
sigbit_with_non_chain_users.insert(bit);
}
-
- if (wire->attributes.count(ID::init)) {
- SigSpec initsig = sigmap(wire);
- Const initval = wire->attributes.at(ID::init);
- for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++)
- if (initval[i] == State::S0 && !opts.zinit)
- sigbit_init[initsig[i]] = false;
- else if (initval[i] == State::S1)
- sigbit_init[initsig[i]] = true;
- }
}
for (auto cell : module->cells())
@@ -137,8 +127,9 @@ struct ShregmapWorker
SigBit d_bit = sigmap(cell->getPort(d_port).as_bit());
SigBit q_bit = sigmap(cell->getPort(q_port).as_bit());
+ State initval = initvals(q_bit);
- if (opts.init || sigbit_init.count(q_bit) == 0)
+ if (opts.init || initval == State::Sx || (opts.zinit && initval == State::S0))
{
auto r = sigbit_chain_next.insert(std::make_pair(d_bit, cell));
if (!r.second) {
@@ -310,22 +301,17 @@ struct ShregmapWorker
if (opts.init) {
vector<State> initval;
for (int i = depth-1; i >= 0; i--) {
- SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit());
- if (sigbit_init.count(bit) == 0)
- initval.push_back(State::Sx);
- else if (sigbit_init.at(bit))
- initval.push_back(State::S1);
- else
- initval.push_back(State::S0);
- remove_init.insert(bit);
+ SigBit bit = chain[cursor+i]->getPort(q_port).as_bit();
+ initval.push_back(initvals(bit));
+ initvals.remove_init(bit);
}
first_cell->setParam(ID::INIT, initval);
}
if (opts.zinit)
for (int i = depth-1; i >= 0; i--) {
- SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit());
- remove_init.insert(bit);
+ SigBit bit = chain[cursor+i]->getPort(q_port).as_bit();
+ initvals.remove_init(bit);
}
if (opts.params)
@@ -364,22 +350,6 @@ struct ShregmapWorker
for (auto cell : remove_cells)
module->remove(cell);
- for (auto wire : module->wires())
- {
- if (wire->attributes.count(ID::init) == 0)
- continue;
-
- SigSpec initsig = sigmap(wire);
- Const &initval = wire->attributes.at(ID::init);
-
- for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++)
- if (remove_init.count(initsig[i]))
- initval[i] = State::Sx;
-
- if (SigSpec(initval).is_fully_undef())
- wire->attributes.erase(ID::init);
- }
-
remove_cells.clear();
sigbit_chain_next.clear();
sigbit_chain_prev.clear();
@@ -389,6 +359,7 @@ struct ShregmapWorker
ShregmapWorker(Module *module, const ShregmapOptions &opts) :
module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0)
{
+ initvals.set(&sigmap, module);
make_sigbit_chain_next_prev();
find_chain_start_cells();
@@ -403,7 +374,7 @@ struct ShregmapWorker
struct ShregmapPass : public Pass {
ShregmapPass() : Pass("shregmap", "map shift registers") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -461,7 +432,7 @@ struct ShregmapPass : public Pass {
log(" map to greenpak4 shift registers.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
ShregmapOptions opts;
string clkpol, enpol;
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index 214157a64..b9d337da4 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -474,29 +474,93 @@ void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
-void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_dffsre(RTLIL::Module *module, RTLIL::Cell *cell)
{
int width = cell->parameters.at(ID::WIDTH).as_int();
char clk_pol = cell->parameters.at(ID::CLK_POLARITY).as_bool() ? 'P' : 'N';
- char rst_pol = cell->parameters.at(ID::ARST_POLARITY).as_bool() ? 'P' : 'N';
+ char set_pol = cell->parameters.at(ID::SET_POLARITY).as_bool() ? 'P' : 'N';
+ char clr_pol = cell->parameters.at(ID::CLR_POLARITY).as_bool() ? 'P' : 'N';
+ char en_pol = cell->parameters.at(ID::EN_POLARITY).as_bool() ? 'P' : 'N';
- std::vector<RTLIL::State> rst_val = cell->parameters.at(ID::ARST_VALUE).bits;
+ RTLIL::SigSpec sig_clk = cell->getPort(ID::CLK);
+ RTLIL::SigSpec sig_s = cell->getPort(ID::SET);
+ RTLIL::SigSpec sig_r = cell->getPort(ID::CLR);
+ RTLIL::SigSpec sig_e = cell->getPort(ID::EN);
+ RTLIL::SigSpec sig_d = cell->getPort(ID::D);
+ RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
+
+ IdString gate_type = stringf("$_DFFSRE_%c%c%c%c_", clk_pol, set_pol, clr_pol, en_pol);
+
+ for (int i = 0; i < width; i++) {
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+ gate->setPort(ID::C, sig_clk);
+ gate->setPort(ID::S, sig_s[i]);
+ gate->setPort(ID::R, sig_r[i]);
+ gate->setPort(ID::E, sig_e);
+ gate->setPort(ID::D, sig_d[i]);
+ gate->setPort(ID::Q, sig_q[i]);
+ }
+}
+
+void simplemap_adff_sdff(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+ int width = cell->parameters.at(ID::WIDTH).as_int();
+ bool is_async = cell->type == ID($adff);
+ char clk_pol = cell->parameters.at(ID::CLK_POLARITY).as_bool() ? 'P' : 'N';
+ char rst_pol = cell->parameters.at(is_async ? ID::ARST_POLARITY : ID::SRST_POLARITY).as_bool() ? 'P' : 'N';
+ const char *type = is_async ? "DFF" : "SDFF";
+
+ std::vector<RTLIL::State> rst_val = cell->parameters.at(is_async ? ID::ARST_VALUE : ID::SRST_VALUE).bits;
while (int(rst_val.size()) < width)
rst_val.push_back(RTLIL::State::S0);
RTLIL::SigSpec sig_clk = cell->getPort(ID::CLK);
- RTLIL::SigSpec sig_rst = cell->getPort(ID::ARST);
+ RTLIL::SigSpec sig_rst = cell->getPort(is_async ? ID::ARST : ID::SRST);
+ RTLIL::SigSpec sig_d = cell->getPort(ID::D);
+ RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
+
+ IdString gate_type_0 = stringf("$_%s_%c%c0_", type, clk_pol, rst_pol);
+ IdString gate_type_1 = stringf("$_%s_%c%c1_", type, clk_pol, rst_pol);
+
+ for (int i = 0; i < width; i++) {
+ RTLIL::Cell *gate = module->addCell(NEW_ID, rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0);
+ gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+ gate->setPort(ID::C, sig_clk);
+ gate->setPort(ID::R, sig_rst);
+ gate->setPort(ID::D, sig_d[i]);
+ gate->setPort(ID::Q, sig_q[i]);
+ }
+}
+
+void simplemap_adffe_sdffe_sdffce(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+ int width = cell->parameters.at(ID::WIDTH).as_int();
+ bool is_async = cell->type == ID($adffe);
+ char clk_pol = cell->parameters.at(ID::CLK_POLARITY).as_bool() ? 'P' : 'N';
+ char rst_pol = cell->parameters.at(is_async ? ID::ARST_POLARITY : ID::SRST_POLARITY).as_bool() ? 'P' : 'N';
+ char en_pol = cell->parameters.at(ID::EN_POLARITY).as_bool() ? 'P' : 'N';
+ const char *type = is_async ? "DFFE" : cell->type == ID($sdffe) ? "SDFFE" : "SDFFCE";
+
+ std::vector<RTLIL::State> rst_val = cell->parameters.at(is_async ? ID::ARST_VALUE : ID::SRST_VALUE).bits;
+ while (int(rst_val.size()) < width)
+ rst_val.push_back(RTLIL::State::S0);
+
+ RTLIL::SigSpec sig_clk = cell->getPort(ID::CLK);
+ RTLIL::SigSpec sig_rst = cell->getPort(is_async ? ID::ARST : ID::SRST);
+ RTLIL::SigSpec sig_e = cell->getPort(ID::EN);
RTLIL::SigSpec sig_d = cell->getPort(ID::D);
RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
- IdString gate_type_0 = stringf("$_DFF_%c%c0_", clk_pol, rst_pol);
- IdString gate_type_1 = stringf("$_DFF_%c%c1_", clk_pol, rst_pol);
+ IdString gate_type_0 = stringf("$_%s_%c%c0%c_", type, clk_pol, rst_pol, en_pol);
+ IdString gate_type_1 = stringf("$_%s_%c%c1%c_", type, clk_pol, rst_pol, en_pol);
for (int i = 0; i < width; i++) {
RTLIL::Cell *gate = module->addCell(NEW_ID, rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0);
gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
gate->setPort(ID::C, sig_clk);
gate->setPort(ID::R, sig_rst);
+ gate->setPort(ID::E, sig_e);
gate->setPort(ID::D, sig_d[i]);
gate->setPort(ID::Q, sig_q[i]);
}
@@ -522,6 +586,60 @@ void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
+void simplemap_adlatch(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+ int width = cell->parameters.at(ID::WIDTH).as_int();
+ char en_pol = cell->parameters.at(ID::EN_POLARITY).as_bool() ? 'P' : 'N';
+ char rst_pol = cell->parameters.at(ID::ARST_POLARITY).as_bool() ? 'P' : 'N';
+
+ std::vector<RTLIL::State> rst_val = cell->parameters.at(ID::ARST_VALUE).bits;
+ while (int(rst_val.size()) < width)
+ rst_val.push_back(RTLIL::State::S0);
+
+ RTLIL::SigSpec sig_en = cell->getPort(ID::EN);
+ RTLIL::SigSpec sig_rst = cell->getPort(ID::ARST);
+ RTLIL::SigSpec sig_d = cell->getPort(ID::D);
+ RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
+
+ IdString gate_type_0 = stringf("$_DLATCH_%c%c0_", en_pol, rst_pol);
+ IdString gate_type_1 = stringf("$_DLATCH_%c%c1_", en_pol, rst_pol);
+
+ for (int i = 0; i < width; i++) {
+ RTLIL::Cell *gate = module->addCell(NEW_ID, rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0);
+ gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+ gate->setPort(ID::E, sig_en);
+ gate->setPort(ID::R, sig_rst);
+ gate->setPort(ID::D, sig_d[i]);
+ gate->setPort(ID::Q, sig_q[i]);
+ }
+}
+
+void simplemap_dlatchsr(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+ int width = cell->parameters.at(ID::WIDTH).as_int();
+ char en_pol = cell->parameters.at(ID::EN_POLARITY).as_bool() ? 'P' : 'N';
+ char set_pol = cell->parameters.at(ID::SET_POLARITY).as_bool() ? 'P' : 'N';
+ char clr_pol = cell->parameters.at(ID::CLR_POLARITY).as_bool() ? 'P' : 'N';
+
+ RTLIL::SigSpec sig_en = cell->getPort(ID::EN);
+ RTLIL::SigSpec sig_s = cell->getPort(ID::SET);
+ RTLIL::SigSpec sig_r = cell->getPort(ID::CLR);
+ RTLIL::SigSpec sig_d = cell->getPort(ID::D);
+ RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
+
+ IdString gate_type = stringf("$_DLATCHSR_%c%c%c_", en_pol, set_pol, clr_pol);
+
+ for (int i = 0; i < width; i++) {
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+ gate->setPort(ID::E, sig_en);
+ gate->setPort(ID::S, sig_s[i]);
+ gate->setPort(ID::R, sig_r[i]);
+ gate->setPort(ID::D, sig_d[i]);
+ gate->setPort(ID::Q, sig_q[i]);
+ }
+}
+
void simplemap_get_mappers(dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers)
{
mappers[ID($not)] = simplemap_not;
@@ -553,8 +671,15 @@ void simplemap_get_mappers(dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)>
mappers[ID($dff)] = simplemap_dff;
mappers[ID($dffe)] = simplemap_dffe;
mappers[ID($dffsr)] = simplemap_dffsr;
- mappers[ID($adff)] = simplemap_adff;
+ mappers[ID($dffsre)] = simplemap_dffsre;
+ mappers[ID($adff)] = simplemap_adff_sdff;
+ mappers[ID($sdff)] = simplemap_adff_sdff;
+ mappers[ID($adffe)] = simplemap_adffe_sdffe_sdffce;
+ mappers[ID($sdffe)] = simplemap_adffe_sdffe_sdffce;
+ mappers[ID($sdffce)] = simplemap_adffe_sdffe_sdffce;
mappers[ID($dlatch)] = simplemap_dlatch;
+ mappers[ID($adlatch)] = simplemap_adlatch;
+ mappers[ID($dlatchsr)] = simplemap_dlatchsr;
}
void simplemap(RTLIL::Module *module, RTLIL::Cell *cell)
@@ -575,7 +700,7 @@ PRIVATE_NAMESPACE_BEGIN
struct SimplemapPass : public Pass {
SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -587,10 +712,10 @@ struct SimplemapPass : public Pass {
log(" $not, $pos, $and, $or, $xor, $xnor\n");
log(" $reduce_and, $reduce_or, $reduce_xor, $reduce_xnor, $reduce_bool\n");
log(" $logic_not, $logic_and, $logic_or, $mux, $tribuf\n");
- log(" $sr, $ff, $dff, $dffsr, $adff, $dlatch\n");
+ log(" $sr, $ff, $dff, $dffe, $dffsr, $dffsre, $adff, $adffe, $sdff, $sdffe, $sdffce, $dlatch, $adlatch, $dlatchsr\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing SIMPLEMAP pass (map simple cells to gate primitives).\n");
extra_args(args, 1, design);
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index 535db9465..d43737c8d 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -20,6 +20,7 @@
#include "kernel/yosys.h"
#include "kernel/utils.h"
#include "kernel/sigtools.h"
+#include "kernel/ffinit.h"
#include "libs/sha1/sha1.h"
#include <stdlib.h>
@@ -232,16 +233,14 @@ struct TechmapWorker
}
}
- SigMap tpl_sigmap(tpl);
pool<SigBit> tpl_written_bits;
-
for (auto tpl_cell : tpl->cells())
for (auto &conn : tpl_cell->connections())
if (tpl_cell->output(conn.first))
- for (auto bit : tpl_sigmap(conn.second))
+ for (auto bit : conn.second)
tpl_written_bits.insert(bit);
for (auto &conn : tpl->connections())
- for (auto bit : tpl_sigmap(conn.first))
+ for (auto bit : conn.first)
tpl_written_bits.insert(bit);
SigMap port_signal_map;
@@ -279,7 +278,7 @@ struct TechmapWorker
SigSpec sig_tpl = w, sig_tpl_pf = w, sig_mod = it.second;
apply_prefix(cell->name, sig_tpl_pf, module);
for (int i = 0; i < GetSize(sig_tpl) && i < GetSize(sig_mod); i++) {
- if (tpl_written_bits.count(tpl_sigmap(sig_tpl[i]))) {
+ if (tpl_written_bits.count(sig_tpl[i])) {
c.first.append(sig_mod[i]);
c.second.append(sig_tpl_pf[i]);
} else {
@@ -328,8 +327,9 @@ struct TechmapWorker
for (auto tpl_cell : tpl->cells())
{
IdString c_name = tpl_cell->name;
+ bool techmap_replace_cell = (c_name == ID::_TECHMAP_REPLACE_);
- if (c_name == ID::_TECHMAP_REPLACE_)
+ if (techmap_replace_cell)
c_name = orig_cell_name;
else if (tpl_cell->name.begins_with("\\_TECHMAP_REPLACE_."))
c_name = stringf("%s%s", orig_cell_name.c_str(), c_name.c_str() + strlen("\\_TECHMAP_REPLACE_"));
@@ -384,7 +384,7 @@ struct TechmapWorker
if (c->attributes.count(ID::src))
c->add_strpool_attribute(ID::src, extra_src_attrs);
- if (c_name == ID::_TECHMAP_REPLACE_)
+ if (techmap_replace_cell)
for (auto attr : cell->attributes)
if (!c->attributes.count(attr.first))
c->attributes[attr.first] = attr.second;
@@ -425,18 +425,7 @@ struct TechmapWorker
LogMakeDebugHdl mkdebug;
SigMap sigmap(module);
-
- dict<SigBit, State> init_bits;
- pool<SigBit> remove_init_bits;
-
- for (auto wire : module->wires()) {
- if (wire->attributes.count(ID::init)) {
- Const value = wire->attributes.at(ID::init);
- for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++)
- if (value[i] != State::Sx)
- init_bits[sigmap(SigBit(wire, i))] = value[i];
- }
- }
+ FfInitVals initvals(&sigmap, module);
TopoSort<RTLIL::Cell*, IdString::compare_ptr_by_name<RTLIL::Cell>> cells;
dict<RTLIL::Cell*, pool<RTLIL::SigBit>> cell_to_inbit;
@@ -642,6 +631,8 @@ struct TechmapWorker
if (tpl->avail_parameters.count(ID::_TECHMAP_CELLTYPE_) != 0)
parameters.emplace(ID::_TECHMAP_CELLTYPE_, RTLIL::unescape_id(cell->type));
+ if (tpl->avail_parameters.count(ID::_TECHMAP_CELLNAME_) != 0)
+ parameters.emplace(ID::_TECHMAP_CELLNAME_, RTLIL::unescape_id(cell->name));
for (auto &conn : cell->connections()) {
if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first))) != 0) {
@@ -658,15 +649,7 @@ struct TechmapWorker
parameters.emplace(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const());
}
if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first))) != 0) {
- auto sig = sigmap(conn.second);
- RTLIL::Const value(State::Sx, sig.size());
- for (int i = 0; i < sig.size(); i++) {
- auto it = init_bits.find(sig[i]);
- if (it != init_bits.end()) {
- value[i] = it->second;
- }
- }
- parameters.emplace(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first)), value);
+ parameters.emplace(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first)), initvals(conn.second));
}
}
@@ -816,11 +799,31 @@ struct TechmapWorker
}
}
+ // Handle outputs first, as these cannot be remapped.
+ for (auto &conn : cell->connections())
+ {
+ Wire *twire = tpl->wire(conn.first);
+ if (!twire->port_output)
+ continue;
+
+ for (int i = 0; i < GetSize(conn.second); i++) {
+ RTLIL::SigBit bit = sigmap(conn.second[i]);
+ RTLIL::SigBit tplbit(twire, i);
+ cellbits_to_tplbits[bit] = tplbit;
+ }
+ }
+
+ // Now handle inputs, remapping as necessary.
for (auto &conn : cell->connections())
+ {
+ Wire *twire = tpl->wire(conn.first);
+ if (twire->port_output)
+ continue;
+
for (int i = 0; i < GetSize(conn.second); i++)
{
RTLIL::SigBit bit = sigmap(conn.second[i]);
- RTLIL::SigBit tplbit(tpl->wire(conn.first), i);
+ RTLIL::SigBit tplbit(twire, i);
if (bit.wire == nullptr)
{
@@ -835,6 +838,7 @@ struct TechmapWorker
else
cellbits_to_tplbits[bit] = tplbit;
}
+ }
RTLIL::SigSig port_conn;
for (auto &it : port_connmap) {
@@ -911,7 +915,7 @@ struct TechmapWorker
auto sig = sigmap(it->second);
for (int i = 0; i < sig.size(); i++)
if (val[i] == State::S1)
- remove_init_bits.insert(sig[i]);
+ initvals.remove_init(sig[i]);
}
}
}
@@ -960,25 +964,6 @@ struct TechmapWorker
handled_cells.insert(cell);
}
- if (!remove_init_bits.empty()) {
- for (auto wire : module->wires())
- if (wire->attributes.count(ID::init)) {
- Const &value = wire->attributes.at(ID::init);
- bool do_cleanup = true;
- for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) {
- SigBit bit = sigmap(SigBit(wire, i));
- if (remove_init_bits.count(bit))
- value[i] = State::Sx;
- else if (value[i] != State::Sx)
- do_cleanup = false;
- }
- if (do_cleanup) {
- log("Removing init attribute from wire %s.%s.\n", log_id(module), log_id(wire));
- wire->attributes.erase(ID::init);
- }
- }
- }
-
if (log_continue) {
log_header(design, "Continuing TECHMAP pass.\n");
log_continue = false;
@@ -991,14 +976,14 @@ struct TechmapWorker
struct TechmapPass : public Pass {
TechmapPass() : Pass("techmap", "generic technology mapper") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" techmap [-map filename] [selection]\n");
log("\n");
log("This pass implements a very simple technology mapper that replaces cells in\n");
- log("the design with implementations given in form of a Verilog or ilang source\n");
+ log("the design with implementations given in form of a Verilog or RTLIL source\n");
log("file.\n");
log("\n");
log(" -map filename\n");
@@ -1041,7 +1026,9 @@ struct TechmapPass : public Pass {
log("\n");
log("When a module in the map file has the 'techmap_celltype' attribute set, it will\n");
log("match cells with a type that match the text value of this attribute. Otherwise\n");
- log("the module name will be used to match the cell.\n");
+ log("the module name will be used to match the cell. Multiple space-separated cell\n");
+ log("types can be listed, and wildcards using [] will be expanded (ie. \"$_DFF_[PN]_\"\n");
+ log("is the same as \"$_DFF_P_ $_DFF_N_\").\n");
log("\n");
log("When a module in the map file has the 'techmap_simplemap' attribute set, techmap\n");
log("will use 'simplemap' (see 'help simplemap') to map cells matching the module.\n");
@@ -1110,6 +1097,10 @@ struct TechmapPass : public Pass {
log(" When a parameter with this name exists, it will be set to the type name\n");
log(" of the cell that matches the module.\n");
log("\n");
+ log(" _TECHMAP_CELLNAME_\n");
+ log(" When a parameter with this name exists, it will be set to the name\n");
+ log(" of the cell that matches the module.\n");
+ log("\n");
log(" _TECHMAP_CONSTMSK_<port-name>_\n");
log(" _TECHMAP_CONSTVAL_<port-name>_\n");
log(" When this pair of parameters is available in a module for a port, then\n");
@@ -1151,7 +1142,7 @@ struct TechmapPass : public Pass {
log("essentially techmap but using the design itself as map library).\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing TECHMAP pass (map to technology primitives).\n");
log_push();
@@ -1219,7 +1210,7 @@ struct TechmapPass : public Pass {
if (!map->module(mod->name))
map->add(mod->clone());
} else {
- Frontend::frontend_call(map, nullptr, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "ilang" : verilog_frontend));
+ Frontend::frontend_call(map, nullptr, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "rtlil" : verilog_frontend));
}
}
@@ -1229,8 +1220,27 @@ struct TechmapPass : public Pass {
for (auto module : map->modules()) {
if (module->attributes.count(ID::techmap_celltype) && !module->attributes.at(ID::techmap_celltype).bits.empty()) {
char *p = strdup(module->attributes.at(ID::techmap_celltype).decode_string().c_str());
- for (char *q = strtok(p, " \t\r\n"); q; q = strtok(nullptr, " \t\r\n"))
- celltypeMap[RTLIL::escape_id(q)].insert(module->name);
+ for (char *q = strtok(p, " \t\r\n"); q; q = strtok(nullptr, " \t\r\n")) {
+ std::vector<std::string> queue;
+ queue.push_back(q);
+ while (!queue.empty()) {
+ std::string name = queue.back();
+ queue.pop_back();
+ auto pos = name.find('[');
+ if (pos == std::string::npos) {
+ // No further expansion.
+ celltypeMap[RTLIL::escape_id(name)].insert(module->name);
+ } else {
+ // Expand [] in this name.
+ auto epos = name.find(']', pos);
+ if (epos == std::string::npos)
+ log_error("Malformed techmap_celltype pattern %s\n", q);
+ for (size_t i = pos + 1; i < epos; i++) {
+ queue.push_back(name.substr(0, pos) + name[i] + name.substr(epos + 1, std::string::npos));
+ }
+ }
+ }
+ }
free(p);
} else {
IdString module_name = module->name.begins_with("\\$") ?
@@ -1238,8 +1248,15 @@ struct TechmapPass : public Pass {
celltypeMap[module_name].insert(module->name);
}
}
- for (auto &i : celltypeMap)
+ log_debug("Cell type mappings to use:\n");
+ for (auto &i : celltypeMap) {
i.second.sort(RTLIL::sort_by_id_str());
+ std::string maps = "";
+ for (auto &map : i.second)
+ maps += stringf(" %s", log_id(map));
+ log_debug(" %s:%s\n", log_id(i.first), maps.c_str());
+ }
+ log_debug("\n");
for (auto module : design->modules())
worker.module_queue.insert(module);
diff --git a/passes/techmap/tribuf.cc b/passes/techmap/tribuf.cc
index 90f3a9d6f..79ddb4bd7 100644
--- a/passes/techmap/tribuf.cc
+++ b/passes/techmap/tribuf.cc
@@ -143,7 +143,7 @@ struct TribufWorker {
struct TribufPass : public Pass {
TribufPass() : Pass("tribuf", "infer tri-state buffers") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -160,7 +160,7 @@ struct TribufPass : public Pass {
log(" to non-tristate logic. this option implies -merge.\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
TribufConfig config;
diff --git a/passes/techmap/zinit.cc b/passes/techmap/zinit.cc
index 74604ba3b..e3b4ae573 100644
--- a/passes/techmap/zinit.cc
+++ b/passes/techmap/zinit.cc
@@ -19,13 +19,14 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
+#include "kernel/ffinit.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct ZinitPass : public Pass {
ZinitPass() : Pass("zinit", "add inverters so all FF are zero-initialized") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -37,7 +38,7 @@ struct ZinitPass : public Pass {
log(" also add zero initialization to uninitialized FFs\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool all_mode = false;
@@ -57,54 +58,35 @@ struct ZinitPass : public Pass {
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
- dict<SigBit, std::pair<State,SigBit>> initbits;
-
- for (auto wire : module->selected_wires())
- {
- if (wire->attributes.count(ID::init) == 0)
- continue;
-
- SigSpec wirebits = sigmap(wire);
- Const initval = wire->attributes.at(ID::init);
-
- for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++)
- {
- SigBit bit = wirebits[i];
- State val = initval[i];
-
- if (val != State::S0 && val != State::S1 && bit.wire != nullptr)
- continue;
-
- if (initbits.count(bit)) {
- if (initbits.at(bit).first != val)
- log_error("Conflicting init values for signal %s (%s = %s != %s).\n",
- log_signal(bit), log_signal(SigBit(wire, i)),
- log_signal(val), log_signal(initbits.at(bit).first));
- continue;
- }
-
- initbits[bit] = std::make_pair(val,SigBit(wire,i));
- }
- }
+ FfInitVals initvals(&sigmap, module);
pool<IdString> dff_types = {
// FIXME: It would appear that supporting
// $dffsr/$_DFFSR_* would require a new
// cell type where S has priority over R
- ID($ff), ID($dff), ID($dffe), /*ID($dffsr),*/ ID($adff),
+ ID($ff), ID($dff), ID($dffe), /*ID($dffsr),*/ ID($adff), ID($adffe),
+ ID($sdff), ID($sdffe), ID($sdffce),
ID($_FF_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_),
/*ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_),*/
ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_),
// Async set/reset
- ID($__DFFE_NN0), ID($__DFFE_NN1), ID($__DFFE_NP0), ID($__DFFE_NP1),
- ID($__DFFE_PN0), ID($__DFFE_PN1), ID($__DFFE_PP0), ID($__DFFE_PP1),
+ ID($_DFFE_NN0P_), ID($_DFFE_NN1P_), ID($_DFFE_NP0P_), ID($_DFFE_NP1P_),
+ ID($_DFFE_PN0P_), ID($_DFFE_PN1P_), ID($_DFFE_PP0P_), ID($_DFFE_PP1P_),
+ ID($_DFFE_NN0N_), ID($_DFFE_NN1N_), ID($_DFFE_NP0N_), ID($_DFFE_NP1N_),
+ ID($_DFFE_PN0N_), ID($_DFFE_PN1N_), ID($_DFFE_PP0N_), ID($_DFFE_PP1N_),
// Sync set/reset
- ID($__DFFS_NN0_), ID($__DFFS_NN1_), ID($__DFFS_NP0_), ID($__DFFS_NP1_),
- ID($__DFFS_PN0_), ID($__DFFS_PN1_), ID($__DFFS_PP0_), ID($__DFFS_PP1_),
- ID($__DFFSE_NN0), ID($__DFFSE_NN1), ID($__DFFSE_NP0), ID($__DFFSE_NP1),
- ID($__DFFSE_PN0), ID($__DFFSE_PN1), ID($__DFFSE_PP0), ID($__DFFSE_PP1)
+ ID($_SDFF_NN0_), ID($_SDFF_NN1_), ID($_SDFF_NP0_), ID($_SDFF_NP1_),
+ ID($_SDFF_PN0_), ID($_SDFF_PN1_), ID($_SDFF_PP0_), ID($_SDFF_PP1_),
+ ID($_SDFFE_NN0P_), ID($_SDFFE_NN1P_), ID($_SDFFE_NP0P_), ID($_SDFFE_NP1P_),
+ ID($_SDFFE_PN0P_), ID($_SDFFE_PN1P_), ID($_SDFFE_PP0P_), ID($_SDFFE_PP1P_),
+ ID($_SDFFE_NN0N_), ID($_SDFFE_NN1N_), ID($_SDFFE_NP0N_), ID($_SDFFE_NP1N_),
+ ID($_SDFFE_PN0N_), ID($_SDFFE_PN1N_), ID($_SDFFE_PP0N_), ID($_SDFFE_PP1N_),
+ ID($_SDFFCE_NN0P_), ID($_SDFFCE_NN1P_), ID($_SDFFCE_NP0P_), ID($_SDFFCE_NP1P_),
+ ID($_SDFFCE_PN0P_), ID($_SDFFCE_PN1P_), ID($_SDFFCE_PP0P_), ID($_SDFFCE_PP1P_),
+ ID($_SDFFCE_NN0N_), ID($_SDFFCE_NN1N_), ID($_SDFFCE_NP0N_), ID($_SDFFCE_NP1N_),
+ ID($_SDFFCE_PN0N_), ID($_SDFFCE_PN1N_), ID($_SDFFCE_PP0N_), ID($_SDFFCE_PP1N_)
};
for (auto cell : module->selected_cells())
@@ -118,46 +100,48 @@ struct ZinitPass : public Pass {
if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1)
continue;
- Const initval;
+ Const initval = initvals(sig_q);
+ Const newval = initval;
+ initvals.remove_init(sig_q);
- for (int i = 0; i < GetSize(sig_q); i++) {
- if (initbits.count(sig_q[i])) {
- const auto &d = initbits.at(sig_q[i]);
- initval.bits.push_back(d.first);
- const auto &b = d.second;
- b.wire->attributes.at(ID::init)[b.offset] = State::Sx;
- } else
- initval.bits.push_back(all_mode ? State::S0 : State::Sx);
- }
-
- Wire *initwire = module->addWire(NEW_ID, GetSize(initval));
- initwire->attributes[ID::init] = initval;
+ Wire *initwire = module->addWire(NEW_ID, GetSize(sig_q));
for (int i = 0; i < GetSize(initwire); i++)
if (initval[i] == State::S1)
{
sig_d[i] = module->NotGate(NEW_ID, sig_d[i]);
module->addNotGate(NEW_ID, SigSpec(initwire, i), sig_q[i]);
- initwire->attributes[ID::init][i] = State::S0;
+ newval[i] = State::S0;
}
else
{
module->connect(sig_q[i], SigSpec(initwire, i));
+ if (all_mode)
+ newval[i] = State::S0;
}
+ initvals.set_init(initwire, newval);
+
log("FF init value for cell %s (%s): %s = %s\n", log_id(cell), log_id(cell->type),
log_signal(sig_q), log_signal(initval));
cell->setPort(ID::D, sig_d);
cell->setPort(ID::Q, initwire);
- if (cell->type == ID($adff)) {
+ if (cell->type.in(ID($adff), ID($adffe))) {
auto val = cell->getParam(ID::ARST_VALUE);
for (int i = 0; i < GetSize(initwire); i++)
if (initval[i] == State::S1)
val[i] = (val[i] == State::S1 ? State::S0 : State::S1);
cell->setParam(ID::ARST_VALUE, std::move(val));
}
+ else if (cell->type.in(ID($sdff), ID($sdffe), ID($sdffce))) {
+ auto val = cell->getParam(ID::SRST_VALUE);
+ for (int i = 0; i < GetSize(initwire); i++)
+ if (initval[i] == State::S1)
+ val[i] = (val[i] == State::S1 ? State::S0 : State::S1);
+ cell->setParam(ID::SRST_VALUE, std::move(val));
+ }
else if (initval == State::S1) {
std::string t = cell->type.str();
if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
@@ -165,15 +149,29 @@ struct ZinitPass : public Pass {
{
t[8] = (t[8] == '0' ? '1' : '0');
}
- else if (cell->type.in(ID($__DFFE_NN0), ID($__DFFE_NN1), ID($__DFFE_NP0), ID($__DFFE_NP1),
- ID($__DFFE_PN0), ID($__DFFE_PN1), ID($__DFFE_PP0), ID($__DFFE_PP1),
- ID($__DFFS_NN0_), ID($__DFFS_NN1_), ID($__DFFS_NP0_), ID($__DFFS_NP1_),
- ID($__DFFS_PN0_), ID($__DFFS_PN1_), ID($__DFFS_PP0_), ID($__DFFS_PP1_)))
+ else if (cell->type.in(ID($_SDFF_NN0_), ID($_SDFF_NN1_), ID($_SDFF_NP0_), ID($_SDFF_NP1_),
+ ID($_SDFF_PN0_), ID($_SDFF_PN1_), ID($_SDFF_PP0_), ID($_SDFF_PP1_)))
+ {
+ t[9] = (t[9] == '0' ? '1' : '0');
+ }
+ else if (cell->type.in(ID($_DFFE_NN0P_), ID($_DFFE_NN1P_), ID($_DFFE_NP0P_), ID($_DFFE_NP1P_),
+ ID($_DFFE_PN0P_), ID($_DFFE_PN1P_), ID($_DFFE_PP0P_), ID($_DFFE_PP1P_),
+ ID($_DFFE_NN0N_), ID($_DFFE_NN1N_), ID($_DFFE_NP0N_), ID($_DFFE_NP1N_),
+ ID($_DFFE_PN0N_), ID($_DFFE_PN1N_), ID($_DFFE_PP0N_), ID($_DFFE_PP1N_)))
+ {
+ t[9] = (t[9] == '0' ? '1' : '0');
+ }
+ else if (cell->type.in(ID($_SDFFE_NN0P_), ID($_SDFFE_NN1P_), ID($_SDFFE_NP0P_), ID($_SDFFE_NP1P_),
+ ID($_SDFFE_PN0P_), ID($_SDFFE_PN1P_), ID($_SDFFE_PP0P_), ID($_SDFFE_PP1P_),
+ ID($_SDFFE_NN0N_), ID($_SDFFE_NN1N_), ID($_SDFFE_NP0N_), ID($_SDFFE_NP1N_),
+ ID($_SDFFE_PN0N_), ID($_SDFFE_PN1N_), ID($_SDFFE_PP0N_), ID($_SDFFE_PP1N_)))
{
t[10] = (t[10] == '0' ? '1' : '0');
}
- else if (cell->type.in(ID($__DFFSE_NN0), ID($__DFFSE_NN1), ID($__DFFSE_NP0), ID($__DFFSE_NP1),
- ID($__DFFSE_PN0), ID($__DFFSE_PN1), ID($__DFFSE_PP0), ID($__DFFSE_PP1)))
+ else if (cell->type.in(ID($_SDFFCE_NN0P_), ID($_SDFFCE_NN1P_), ID($_SDFFCE_NP0P_), ID($_SDFFCE_NP1P_),
+ ID($_SDFFCE_PN0P_), ID($_SDFFCE_PN1P_), ID($_SDFFCE_PP0P_), ID($_SDFFCE_PP1P_),
+ ID($_SDFFCE_NN0N_), ID($_SDFFCE_NN1N_), ID($_SDFFCE_NP0N_), ID($_SDFFCE_NP1N_),
+ ID($_SDFFCE_PN0N_), ID($_SDFFCE_PN1N_), ID($_SDFFCE_PP0N_), ID($_SDFFCE_PP1N_)))
{
t[11] = (t[11] == '0' ? '1' : '0');
}
diff --git a/passes/tests/test_abcloop.cc b/passes/tests/test_abcloop.cc
index 894610e2b..ac31e36f1 100644
--- a/passes/tests/test_abcloop.cc
+++ b/passes/tests/test_abcloop.cc
@@ -132,7 +132,7 @@ static void test_abcloop()
SatGen satgen(ez.get(), &sigmap);
for (auto c : module->cells()) {
- bool ok YS_ATTRIBUTE(unused) = satgen.importCell(c);
+ bool ok = satgen.importCell(c);
log_assert(ok);
}
@@ -171,7 +171,7 @@ static void test_abcloop()
}
log("Found viable UUT after %d cycles:\n", create_cycles);
- Pass::call(design, "write_ilang");
+ Pass::call(design, "write_rtlil");
Pass::call(design, "abc");
log("\n");
@@ -182,7 +182,7 @@ static void test_abcloop()
SatGen satgen(ez.get(), &sigmap);
for (auto c : module->cells()) {
- bool ok YS_ATTRIBUTE(unused) = satgen.importCell(c);
+ bool ok = satgen.importCell(c);
log_assert(ok);
}
@@ -244,7 +244,7 @@ static void test_abcloop()
struct TestAbcloopPass : public Pass {
TestAbcloopPass() : Pass("test_abcloop", "automatically test handling of loops in abc command") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -259,7 +259,7 @@ struct TestAbcloopPass : public Pass {
log(" use this value as rng seed value (default = unix time).\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design*) override
{
int num_iter = 100;
xorshift32_state = 0;
diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc
index 19f21493d..4ab46014d 100644
--- a/passes/tests/test_autotb.cc
+++ b/passes/tests/test_autotb.cc
@@ -327,7 +327,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int s
struct TestAutotbBackend : public Backend {
TestAutotbBackend() : Backend("=test_autotb", "generate simple test benches") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -360,7 +360,7 @@ struct TestAutotbBackend : public Backend {
log(" the current system time.\n");
log("\n");
}
- void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
{
int num_iter = 1000;
int seed = 0;
diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc
index c6801007d..616981f32 100644
--- a/passes/tests/test_cell.cc
+++ b/passes/tests/test_cell.cc
@@ -264,6 +264,14 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
cell->setPort(ID::Y, wire);
}
+ if (cell_type.in(ID($shiftx))) {
+ cell->parameters[ID::A_SIGNED] = false;
+ }
+
+ if (cell_type.in(ID($shl), ID($shr), ID($sshl), ID($sshr))) {
+ cell->parameters[ID::B_SIGNED] = false;
+ }
+
if (muxdiv && cell_type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) {
auto b_not_zero = module->ReduceBool(NEW_ID, cell->getPort(ID::B));
auto div_out = module->addWire(NEW_ID, GetSize(cell->getPort(ID::Y)));
@@ -652,7 +660,7 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
struct TestCellPass : public Pass {
TestCellPass() : Pass("test_cell", "automatically test the implementation of a cell type") { }
- void help() YS_OVERRIDE
+ void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -670,12 +678,12 @@ struct TestCellPass : public Pass {
log(" -s {positive_integer}\n");
log(" use this value as rng seed value (default = unix time).\n");
log("\n");
- log(" -f {ilang_file}\n");
- log(" don't generate circuits. instead load the specified ilang file.\n");
+ log(" -f {rtlil_file}\n");
+ log(" don't generate circuits. instead load the specified RTLIL file.\n");
log("\n");
log(" -w {filename_prefix}\n");
log(" don't test anything. just generate the circuits and write them\n");
- log(" to ilang files with the specified prefix\n");
+ log(" to RTLIL files with the specified prefix\n");
log("\n");
log(" -map {filename}\n");
log(" pass this option to techmap.\n");
@@ -712,11 +720,11 @@ struct TestCellPass : public Pass {
log(" create a Verilog test bench to test simlib and write_verilog\n");
log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design*) override
{
int num_iter = 100;
std::string techmap_cmd = "techmap -assert";
- std::string ilang_file, write_prefix;
+ std::string rtlil_file, write_prefix;
xorshift32_state = 0;
std::ofstream vlog_file;
bool muxdiv = false;
@@ -742,7 +750,7 @@ struct TestCellPass : public Pass {
continue;
}
if (args[argidx] == "-f" && argidx+1 < GetSize(args)) {
- ilang_file = args[++argidx];
+ rtlil_file = args[++argidx];
num_iter = 1;
continue;
}
@@ -902,10 +910,10 @@ struct TestCellPass : public Pass {
selected_cell_types.push_back(args[argidx]);
}
- if (!ilang_file.empty()) {
+ if (!rtlil_file.empty()) {
if (!selected_cell_types.empty())
log_cmd_error("Do not specify any cell types when using -f.\n");
- selected_cell_types.push_back("ilang");
+ selected_cell_types.push_back(ID(rtlil));
}
if (selected_cell_types.empty())
@@ -917,12 +925,12 @@ struct TestCellPass : public Pass {
for (int i = 0; i < num_iter; i++)
{
RTLIL::Design *design = new RTLIL::Design;
- if (cell_type == "ilang")
- Frontend::frontend_call(design, NULL, std::string(), "ilang " + ilang_file);
+ if (cell_type == ID(rtlil))
+ Frontend::frontend_call(design, NULL, std::string(), "rtlil " + rtlil_file);
else
create_gold_module(design, cell_type, cell_types.at(cell_type), constmode, muxdiv);
if (!write_prefix.empty()) {
- Pass::call(design, stringf("write_ilang %s_%s_%05d.il", write_prefix.c_str(), cell_type.c_str()+1, i));
+ Pass::call(design, stringf("write_rtlil %s_%s_%05d.il", write_prefix.c_str(), cell_type.c_str()+1, i));
} else if (edges) {
Pass::call(design, "dump gold");
run_edges_test(design, verbose);