aboutsummaryrefslogtreecommitdiffstats
path: root/passes/techmap
diff options
context:
space:
mode:
Diffstat (limited to 'passes/techmap')
-rw-r--r--passes/techmap/Makefile.inc2
-rw-r--r--passes/techmap/abc.cc412
-rw-r--r--passes/techmap/abc9.cc8
-rw-r--r--passes/techmap/abc9_ops.cc82
-rw-r--r--passes/techmap/bmuxmap.cc76
-rw-r--r--passes/techmap/demuxmap.cc80
-rw-r--r--passes/techmap/dfflegalize.cc1866
-rw-r--r--passes/techmap/dffunmap.cc13
-rw-r--r--passes/techmap/extract_reduce.cc107
-rw-r--r--passes/techmap/flatten.cc7
-rw-r--r--passes/techmap/iopadmap.cc31
-rw-r--r--passes/techmap/simplemap.cc332
-rw-r--r--passes/techmap/simplemap.h7
-rw-r--r--passes/techmap/techmap.cc4
-rw-r--r--passes/techmap/tribuf.cc49
-rw-r--r--passes/techmap/zinit.cc123
16 files changed, 1570 insertions, 1629 deletions
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index 035699603..98ccfc303 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -29,6 +29,8 @@ OBJS += passes/techmap/extract_reduce.o
OBJS += passes/techmap/alumacc.o
OBJS += passes/techmap/dffinit.o
OBJS += passes/techmap/pmuxtree.o
+OBJS += passes/techmap/bmuxmap.o
+OBJS += passes/techmap/demuxmap.o
OBJS += passes/techmap/muxcover.o
OBJS += passes/techmap/aigmap.o
OBJS += passes/techmap/tribuf.o
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index 49a0fad77..ff98a6e36 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -45,6 +45,7 @@
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/ffinit.h"
+#include "kernel/ff.h"
#include "kernel/cost.h"
#include "kernel/log.h"
#include <stdlib.h>
@@ -73,6 +74,8 @@ PRIVATE_NAMESPACE_BEGIN
enum class gate_type_t {
G_NONE,
G_FF,
+ G_FF0,
+ G_FF1,
G_BUF,
G_NOT,
G_AND,
@@ -112,13 +115,14 @@ int map_autoidx;
SigMap assign_map;
RTLIL::Module *module;
std::vector<gate_t> signal_list;
-std::map<RTLIL::SigBit, int> signal_map;
+dict<RTLIL::SigBit, int> signal_map;
FfInitVals initvals;
pool<std::string> enabled_gates;
-bool recover_init, cmos_cost;
+bool cmos_cost;
+bool had_init;
-bool clk_polarity, en_polarity;
-RTLIL::SigSpec clk_sig, en_sig;
+bool clk_polarity, en_polarity, arst_polarity, srst_polarity;
+RTLIL::SigSpec clk_sig, en_sig, arst_sig, srst_sig;
dict<int, std::string> pi_map, po_map;
int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1)
@@ -165,46 +169,84 @@ void mark_port(RTLIL::SigSpec sig)
void extract_cell(RTLIL::Cell *cell, bool keepff)
{
- if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
- {
- if (clk_polarity != (cell->type == ID($_DFF_P_)))
+ if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
+ FfData ff(&initvals, cell);
+ gate_type_t type = G(FF);
+ if (!ff.has_clk)
return;
- if (clk_sig != assign_map(cell->getPort(ID::C)))
+ if (ff.has_gclk)
return;
- if (GetSize(en_sig) != 0)
+ if (ff.has_aload)
return;
- goto matching_dff;
- }
-
- if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
- {
- if (clk_polarity != cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_)))
+ if (ff.has_sr)
return;
- if (en_polarity != cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)))
+ if (!ff.is_fine)
return;
- if (clk_sig != assign_map(cell->getPort(ID::C)))
+ if (clk_polarity != ff.pol_clk)
return;
- if (en_sig != assign_map(cell->getPort(ID::E)))
+ if (clk_sig != assign_map(ff.sig_clk))
return;
- goto matching_dff;
- }
-
- if (0) {
- matching_dff:
- RTLIL::SigSpec sig_d = cell->getPort(ID::D);
- RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
+ if (ff.has_ce) {
+ if (en_polarity != ff.pol_ce)
+ return;
+ if (en_sig != assign_map(ff.sig_ce))
+ return;
+ } else {
+ if (GetSize(en_sig) != 0)
+ return;
+ }
+ if (ff.val_init == State::S1) {
+ type = G(FF1);
+ had_init = true;
+ } else if (ff.val_init == State::S0) {
+ type = G(FF0);
+ had_init = true;
+ }
+ if (ff.has_arst) {
+ if (arst_polarity != ff.pol_arst)
+ return;
+ if (arst_sig != assign_map(ff.sig_arst))
+ return;
+ if (ff.val_arst == State::S1) {
+ if (type == G(FF0))
+ return;
+ type = G(FF1);
+ } else if (ff.val_arst == State::S0) {
+ if (type == G(FF1))
+ return;
+ type = G(FF0);
+ }
+ } else {
+ if (GetSize(arst_sig) != 0)
+ return;
+ }
+ if (ff.has_srst) {
+ if (srst_polarity != ff.pol_srst)
+ return;
+ if (srst_sig != assign_map(ff.sig_srst))
+ return;
+ if (ff.val_srst == State::S1) {
+ if (type == G(FF0))
+ return;
+ type = G(FF1);
+ } else if (ff.val_srst == State::S0) {
+ if (type == G(FF1))
+ return;
+ type = G(FF0);
+ }
+ } else {
+ if (GetSize(srst_sig) != 0)
+ return;
+ }
if (keepff)
- for (auto &c : sig_q.chunks())
+ for (auto &c : ff.sig_q.chunks())
if (c.wire != nullptr)
c.wire->attributes[ID::keep] = 1;
- assign_map.apply(sig_d);
- assign_map.apply(sig_q);
-
- map_signal(sig_q, G(FF), map_signal(sig_d));
+ map_signal(ff.sig_q, type, map_signal(ff.sig_d));
- module->remove(cell);
+ ff.remove();
return;
}
@@ -367,7 +409,7 @@ std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullp
return stringf("$abc$%d$%s", map_autoidx, abc_name.c_str()+1);
}
-void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edges, std::set<int> &workpool, std::vector<int> &in_counts)
+void dump_loop_graph(FILE *f, int &nr, dict<int, pool<int>> &edges, pool<int> &workpool, std::vector<int> &in_counts)
{
if (f == nullptr)
return;
@@ -378,7 +420,7 @@ void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edges, std:
fprintf(f, " label=\"slide%d\";\n", nr);
fprintf(f, " rankdir=\"TD\";\n");
- std::set<int> nodes;
+ pool<int> nodes;
for (auto &e : edges) {
nodes.insert(e.first);
for (auto n : e.second)
@@ -401,9 +443,9 @@ void handle_loops()
// http://en.wikipedia.org/wiki/Topological_sorting
// (Kahn, Arthur B. (1962), "Topological sorting of large networks")
- std::map<int, std::set<int>> edges;
+ dict<int, pool<int>> edges;
std::vector<int> in_edges_count(signal_list.size());
- std::set<int> workpool;
+ pool<int> workpool;
FILE *dot_f = nullptr;
int dot_nr = 0;
@@ -412,7 +454,7 @@ void handle_loops()
// dot_f = fopen("test.dot", "w");
for (auto &g : signal_list) {
- if (g.type == G(NONE) || g.type == G(FF)) {
+ if (g.type == G(NONE) || g.type == G(FF) || g.type == G(FF0) || g.type == G(FF1)) {
workpool.insert(g.id);
} else {
if (g.in1 >= 0) {
@@ -655,8 +697,9 @@ struct abc_output_filter
};
void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
- std::vector<std::string> &liberty_files, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
- bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode,
+ std::vector<std::string> &liberty_files, std::vector<std::string> &genlib_files, std::string constr_file,
+ bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target,
+ std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode,
const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode, bool abc_dress)
{
module = current_module;
@@ -666,7 +709,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
signal_list.clear();
pi_map.clear();
po_map.clear();
- recover_init = false;
if (clk_str != "$")
{
@@ -675,14 +717,41 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
en_polarity = true;
en_sig = RTLIL::SigSpec();
+
+ arst_polarity = true;
+ arst_sig = RTLIL::SigSpec();
+
+ srst_polarity = true;
+ srst_sig = RTLIL::SigSpec();
}
if (!clk_str.empty() && clk_str != "$")
{
+ std::string en_str;
+ std::string arst_str;
+ std::string srst_str;
if (clk_str.find(',') != std::string::npos) {
int pos = clk_str.find(',');
- std::string en_str = clk_str.substr(pos+1);
+ en_str = clk_str.substr(pos+1);
clk_str = clk_str.substr(0, pos);
+ }
+ if (en_str.find(',') != std::string::npos) {
+ int pos = en_str.find(',');
+ arst_str = en_str.substr(pos+1);
+ arst_str = en_str.substr(0, pos);
+ }
+ if (arst_str.find(',') != std::string::npos) {
+ int pos = arst_str.find(',');
+ srst_str = arst_str.substr(pos+1);
+ srst_str = arst_str.substr(0, pos);
+ }
+ if (clk_str[0] == '!') {
+ clk_polarity = false;
+ clk_str = clk_str.substr(1);
+ }
+ if (module->wire(RTLIL::escape_id(clk_str)) != nullptr)
+ clk_sig = assign_map(module->wire(RTLIL::escape_id(clk_str)));
+ if (en_str != "") {
if (en_str[0] == '!') {
en_polarity = false;
en_str = en_str.substr(1);
@@ -690,12 +759,22 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (module->wire(RTLIL::escape_id(en_str)) != nullptr)
en_sig = assign_map(module->wire(RTLIL::escape_id(en_str)));
}
- if (clk_str[0] == '!') {
- clk_polarity = false;
- clk_str = clk_str.substr(1);
+ if (arst_str != "") {
+ if (arst_str[0] == '!') {
+ arst_polarity = false;
+ arst_str = arst_str.substr(1);
+ }
+ if (module->wire(RTLIL::escape_id(arst_str)) != nullptr)
+ arst_sig = assign_map(module->wire(RTLIL::escape_id(arst_str)));
+ }
+ if (srst_str != "") {
+ if (srst_str[0] == '!') {
+ srst_polarity = false;
+ srst_str = srst_str.substr(1);
+ }
+ if (module->wire(RTLIL::escape_id(srst_str)) != nullptr)
+ srst_sig = assign_map(module->wire(RTLIL::escape_id(srst_str)));
}
- if (module->wire(RTLIL::escape_id(clk_str)) != nullptr)
- clk_sig = assign_map(module->wire(RTLIL::escape_id(clk_str)));
}
if (dff_mode && clk_sig.empty())
@@ -710,8 +789,11 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
std::string abc_script = stringf("read_blif %s/input.blif; ", tempdir_name.c_str());
- if (!liberty_files.empty()) {
- for (std::string liberty_file : liberty_files) abc_script += stringf("read_lib -w %s; ", liberty_file.c_str());
+ if (!liberty_files.empty() || !genlib_files.empty()) {
+ for (std::string liberty_file : liberty_files)
+ abc_script += stringf("read_lib -w %s; ", liberty_file.c_str());
+ for (std::string liberty_file : genlib_files)
+ abc_script += stringf("read_library %s; ", liberty_file.c_str());
if (!constr_file.empty())
abc_script += stringf("read_constr -v %s; ", constr_file.c_str());
} else
@@ -739,7 +821,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
if (all_luts_cost_same && !fast_mode)
abc_script += "; lutpack {S}";
- } else if (!liberty_files.empty())
+ } else if (!liberty_files.empty() || !genlib_files.empty())
abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
else if (sop_mode)
abc_script += fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP;
@@ -753,10 +835,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3);
- for (size_t pos = abc_script.find("{I}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
+ for (size_t pos = abc_script.find("{I}"); pos != std::string::npos; pos = abc_script.find("{I}", pos))
abc_script = abc_script.substr(0, pos) + sop_inputs + abc_script.substr(pos+3);
- for (size_t pos = abc_script.find("{P}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
+ for (size_t pos = abc_script.find("{P}"); pos != std::string::npos; pos = abc_script.find("{P}", pos))
abc_script = abc_script.substr(0, pos) + sop_products + abc_script.substr(pos+3);
for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos))
@@ -785,10 +867,15 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
log("Found%s %s clock domain: %s", clk_str.empty() ? "" : " matching", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig));
if (en_sig.size() != 0)
log(", enabled by %s%s", en_polarity ? "" : "!", log_signal(en_sig));
+ if (arst_sig.size() != 0)
+ log(", asynchronously reset by %s%s", arst_polarity ? "" : "!", log_signal(arst_sig));
+ if (srst_sig.size() != 0)
+ log(", synchronously reset by %s%s", srst_polarity ? "" : "!", log_signal(srst_sig));
log("\n");
}
}
+ had_init = false;
for (auto c : cells)
extract_cell(c, keepff);
@@ -807,6 +894,12 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (en_sig.size() != 0)
mark_port(en_sig);
+ if (arst_sig.size() != 0)
+ mark_port(arst_sig);
+
+ if (srst_sig.size() != 0)
+ mark_port(srst_sig);
+
handle_loops();
buffer = stringf("%s/input.blif", tempdir_name.c_str());
@@ -913,11 +1006,11 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
fprintf(f, "00-- 1\n");
fprintf(f, "--00 1\n");
} else if (si.type == G(FF)) {
- if (si.init == State::S0 || si.init == State::S1) {
- fprintf(f, ".latch ys__n%d ys__n%d %d\n", si.in1, si.id, si.init == State::S1 ? 1 : 0);
- recover_init = true;
- } else
- fprintf(f, ".latch ys__n%d ys__n%d 2\n", si.in1, si.id);
+ fprintf(f, ".latch ys__n%d ys__n%d 2\n", si.in1, si.id);
+ } else if (si.type == G(FF0)) {
+ fprintf(f, ".latch ys__n%d ys__n%d 0\n", si.in1, si.id);
+ } else if (si.type == G(FF1)) {
+ fprintf(f, ".latch ys__n%d ys__n%d 1\n", si.in1, si.id);
} else if (si.type != G(NONE))
log_abort();
if (si.type != G(NONE))
@@ -1020,7 +1113,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (ifs.fail())
log_error("Can't open ABC output file `%s'.\n", buffer.c_str());
- bool builtin_lib = liberty_files.empty();
+ bool builtin_lib = liberty_files.empty() && genlib_files.empty();
RTLIL::Design *mapped_design = new RTLIL::Design;
parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, sop_mode);
@@ -1039,7 +1132,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
design->select(module, wire);
}
- std::map<std::string, int> cell_stats;
+ SigMap mapped_sigmap(mapped_mod);
+ FfInitVals mapped_initvals(&mapped_sigmap, mapped_mod);
+
+ dict<std::string, int> cell_stats;
for (auto c : mapped_mod->cells())
{
if (builtin_lib)
@@ -1145,20 +1241,41 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
}
if (c->type == ID(DFF)) {
log_assert(clk_sig.size() == 1);
- RTLIL::Cell *cell;
- if (en_sig.size() == 0) {
- cell = module->addCell(remap_name(c->name), clk_polarity ? ID($_DFF_P_) : ID($_DFF_N_));
- } else {
+ FfData ff(module, &initvals, remap_name(c->name));
+ ff.width = 1;
+ ff.is_fine = true;
+ ff.has_clk = true;
+ ff.pol_clk = clk_polarity;
+ ff.sig_clk = clk_sig;
+ if (en_sig.size() != 0) {
log_assert(en_sig.size() == 1);
- cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
- cell->setPort(ID::E, en_sig);
+ ff.has_ce = true;
+ ff.pol_ce = en_polarity;
+ ff.sig_ce = en_sig;
}
- if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
- for (auto name : {ID::D, ID::Q}) {
- RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name);
- cell->setPort(name, module->wire(remapped_name));
+ RTLIL::Const init = mapped_initvals(c->getPort(ID::Q));
+ if (had_init)
+ ff.val_init = init;
+ else
+ ff.val_init = State::Sx;
+ if (arst_sig.size() != 0) {
+ log_assert(arst_sig.size() == 1);
+ ff.has_arst = true;
+ ff.pol_arst = arst_polarity;
+ ff.sig_arst = arst_sig;
+ ff.val_arst = init;
}
- cell->setPort(ID::C, clk_sig);
+ if (srst_sig.size() != 0) {
+ log_assert(srst_sig.size() == 1);
+ ff.has_srst = true;
+ ff.pol_srst = srst_polarity;
+ ff.sig_srst = srst_sig;
+ ff.val_srst = init;
+ }
+ ff.sig_d = module->wire(remap_name(c->getPort(ID::D).as_wire()->name));
+ ff.sig_q = module->wire(remap_name(c->getPort(ID::Q).as_wire()->name));
+ RTLIL::Cell *cell = ff.emit();
+ if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
design->select(module, cell);
continue;
}
@@ -1176,20 +1293,38 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (c->type == ID(_dff_)) {
log_assert(clk_sig.size() == 1);
- RTLIL::Cell *cell;
- if (en_sig.size() == 0) {
- cell = module->addCell(remap_name(c->name), clk_polarity ? ID($_DFF_P_) : ID($_DFF_N_));
- } else {
+ FfData ff(module, &initvals, remap_name(c->name));
+ ff.width = 1;
+ ff.is_fine = true;
+ ff.has_clk = true;
+ ff.pol_clk = clk_polarity;
+ ff.sig_clk = clk_sig;
+ if (en_sig.size() != 0) {
log_assert(en_sig.size() == 1);
- cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
- cell->setPort(ID::E, en_sig);
+ ff.pol_ce = en_polarity;
+ ff.sig_ce = en_sig;
}
- if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
- for (auto name : {ID::D, ID::Q}) {
- RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name);
- cell->setPort(name, module->wire(remapped_name));
+ RTLIL::Const init = mapped_initvals(c->getPort(ID::Q));
+ if (had_init)
+ ff.val_init = init;
+ else
+ ff.val_init = State::Sx;
+ if (arst_sig.size() != 0) {
+ log_assert(arst_sig.size() == 1);
+ ff.pol_arst = arst_polarity;
+ ff.sig_arst = arst_sig;
+ ff.val_arst = init;
}
- cell->setPort(ID::C, clk_sig);
+ if (srst_sig.size() != 0) {
+ log_assert(srst_sig.size() == 1);
+ ff.pol_srst = srst_polarity;
+ ff.sig_srst = srst_sig;
+ ff.val_srst = init;
+ }
+ ff.sig_d = module->wire(remap_name(c->getPort(ID::D).as_wire()->name));
+ ff.sig_q = module->wire(remap_name(c->getPort(ID::Q).as_wire()->name));
+ RTLIL::Cell *cell = ff.emit();
+ if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
design->select(module, cell);
continue;
}
@@ -1225,15 +1360,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
module->connect(conn);
}
- if (recover_init)
- for (auto wire : mapped_mod->wires()) {
- if (wire->attributes.count(ID::init)) {
- Wire *w = module->wire(remap_name(wire->name));
- log_assert(w->attributes.count(ID::init) == 0);
- w->attributes[ID::init] = wire->attributes.at(ID::init);
- }
- }
-
for (auto &it : cell_stats)
log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second);
int in_wires = 0, out_wires = 0;
@@ -1302,10 +1428,10 @@ struct AbcPass : public Pass {
log("\n");
log(" if no -script parameter is given, the following scripts are used:\n");
log("\n");
- log(" for -liberty without -constr:\n");
+ log(" for -liberty/-genlib without -constr:\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_LIB).c_str());
log("\n");
- log(" for -liberty with -constr:\n");
+ log(" for -liberty/-genlib with -constr:\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_CTR).c_str());
log("\n");
log(" for -lut/-luts (only one LUT size):\n");
@@ -1324,10 +1450,10 @@ struct AbcPass : public Pass {
log(" use different default scripts that are slightly faster (at the cost\n");
log(" of output quality):\n");
log("\n");
- log(" for -liberty without -constr:\n");
+ log(" for -liberty/-genlib without -constr:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LIB).c_str());
log("\n");
- log(" for -liberty with -constr:\n");
+ log(" for -liberty/-genlib with -constr:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_CTR).c_str());
log("\n");
log(" for -lut/-luts:\n");
@@ -1343,8 +1469,13 @@ struct AbcPass : public Pass {
log(" generate netlists for the specified cell library (using the liberty\n");
log(" file format).\n");
log("\n");
+ log(" -genlib <file>\n");
+ log(" generate netlists for the specified cell library (using the SIS Genlib\n");
+ log(" file format).\n");
+ log("\n");
log(" -constr <file>\n");
- log(" pass this file with timing constraints to ABC. use with -liberty.\n");
+ log(" pass this file with timing constraints to ABC.\n");
+ log(" use with -liberty/-genlib.\n");
log("\n");
log(" a constr file contains two lines:\n");
log(" set_driving_cell <cell_name>\n");
@@ -1390,7 +1521,7 @@ struct AbcPass : public Pass {
log("\n");
// log(" -mux4, -mux8, -mux16\n");
// log(" try to extract 4-input, 8-input, and/or 16-input muxes\n");
- // log(" (ignored when used with -liberty or -lut)\n");
+ // log(" (ignored when used with -liberty/-genlib or -lut)\n");
// log("\n");
log(" -g type1,type2,...\n");
log(" Map to the specified list of gate types. Supported gates types are:\n");
@@ -1446,7 +1577,7 @@ struct AbcPass : public Pass {
log(" preserve naming by an equivalence check between the original and post-ABC\n");
log(" netlists (experimental).\n");
log("\n");
- log("When neither -liberty nor -lut is used, the Yosys standard cell library is\n");
+ log("When no target cell library is specified the Yosys standard cell library is\n");
log("loaded into ABC before the ABC script is executed.\n");
log("\n");
log("Note that this is a logic optimization pass within Yosys that is calling ABC\n");
@@ -1473,7 +1604,7 @@ struct AbcPass : public Pass {
std::string exe_file = yosys_abc_executable;
std::string script_file, default_liberty_file, constr_file, clk_str;
- std::vector<std::string> liberty_files;
+ std::vector<std::string> liberty_files, genlib_files;
std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1";
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
bool show_tempdir = false, sop_mode = false;
@@ -1556,6 +1687,10 @@ struct AbcPass : public Pass {
liberty_files.push_back(args[++argidx]);
continue;
}
+ if (arg == "-genlib" && argidx+1 < args.size()) {
+ genlib_files.push_back(args[++argidx]);
+ continue;
+ }
if (arg == "-constr" && argidx+1 < args.size()) {
constr_file = args[++argidx];
continue;
@@ -1645,7 +1780,8 @@ struct AbcPass : public Pass {
}
extra_args(args, argidx, design);
- if (liberty_files.empty() && !default_liberty_file.empty()) liberty_files.push_back(default_liberty_file);
+ if (genlib_files.empty() && liberty_files.empty() && !default_liberty_file.empty())
+ liberty_files.push_back(default_liberty_file);
rewrite_filename(script_file);
if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+')
@@ -1655,6 +1791,11 @@ struct AbcPass : public Pass {
if (!liberty_files[i].empty() && !is_absolute_path(liberty_files[i]))
liberty_files[i] = std::string(pwd) + "/" + liberty_files[i];
}
+ for (int i = 0; i < GetSize(genlib_files); i++) {
+ rewrite_filename(genlib_files[i]);
+ if (!genlib_files[i].empty() && !is_absolute_path(genlib_files[i]))
+ genlib_files[i] = std::string(pwd) + "/" + genlib_files[i];
+ }
rewrite_filename(constr_file);
if (!constr_file.empty() && !is_absolute_path(constr_file))
constr_file = std::string(pwd) + "/" + constr_file;
@@ -1818,10 +1959,10 @@ struct AbcPass : public Pass {
}
}
- if (!lut_costs.empty() && !liberty_files.empty())
- log_cmd_error("Got -lut and -liberty! These two options are exclusive.\n");
- if (!constr_file.empty() && liberty_files.empty())
- log_cmd_error("Got -constr but no -liberty!\n");
+ if (!lut_costs.empty() && !(liberty_files.empty() && genlib_files.empty()))
+ log_cmd_error("Got -lut and -liberty/-genlib! These two options are exclusive.\n");
+ if (!constr_file.empty() && (liberty_files.empty() && genlib_files.empty()))
+ log_cmd_error("Got -constr but no -liberty/-genlib!\n");
if (enabled_gates.empty()) {
enabled_gates.insert("AND");
@@ -1851,7 +1992,7 @@ struct AbcPass : public Pass {
initvals.set(&assign_map, mod);
if (!dff_mode || !clk_str.empty()) {
- abc_module(design, mod, script_file, exe_file, liberty_files, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
+ abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress);
continue;
}
@@ -1859,18 +2000,18 @@ struct AbcPass : public Pass {
CellTypes ct(design);
std::vector<RTLIL::Cell*> all_cells = mod->selected_cells();
- std::set<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end());
+ pool<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end());
- std::set<RTLIL::Cell*> expand_queue, next_expand_queue;
- std::set<RTLIL::Cell*> expand_queue_up, next_expand_queue_up;
- std::set<RTLIL::Cell*> expand_queue_down, next_expand_queue_down;
+ pool<RTLIL::Cell*> expand_queue, next_expand_queue;
+ pool<RTLIL::Cell*> expand_queue_up, next_expand_queue_up;
+ pool<RTLIL::Cell*> expand_queue_down, next_expand_queue_down;
- typedef tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
- std::map<clkdomain_t, std::vector<RTLIL::Cell*>> assigned_cells;
- std::map<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse;
+ typedef tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec, bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
+ dict<clkdomain_t, std::vector<RTLIL::Cell*>> assigned_cells;
+ dict<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse;
- std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_bit, cell_to_bit_up, cell_to_bit_down;
- std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> bit_to_cell, bit_to_cell_up, bit_to_cell_down;
+ dict<RTLIL::Cell*, pool<RTLIL::SigBit>> cell_to_bit, cell_to_bit_up, cell_to_bit_down;
+ dict<RTLIL::SigBit, pool<RTLIL::Cell*>> bit_to_cell, bit_to_cell_up, bit_to_cell_down;
for (auto cell : all_cells)
{
@@ -1893,19 +2034,30 @@ struct AbcPass : public Pass {
}
}
- if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
- {
- key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID::C)), true, RTLIL::SigSpec());
- }
- else
- if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
- {
- bool this_clk_pol = cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_));
- bool this_en_pol = cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_));
- key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(ID::C)), this_en_pol, assign_map(cell->getPort(ID::E)));
- }
- else
+ if (!RTLIL::builtin_ff_cell_types().count(cell->type))
+ continue;
+
+ FfData ff(&initvals, cell);
+ if (!ff.has_clk)
+ continue;
+ if (ff.has_gclk)
+ continue;
+ if (ff.has_aload)
+ continue;
+ if (ff.has_sr)
+ continue;
+ if (!ff.is_fine)
continue;
+ key = clkdomain_t(
+ ff.pol_clk,
+ ff.sig_clk,
+ ff.has_ce ? ff.pol_ce : true,
+ ff.has_ce ? assign_map(ff.sig_ce) : RTLIL::SigSpec(),
+ ff.has_arst ? ff.pol_arst : true,
+ ff.has_arst ? assign_map(ff.sig_arst) : RTLIL::SigSpec(),
+ ff.has_srst ? ff.pol_srst : true,
+ ff.has_srst ? assign_map(ff.sig_srst) : RTLIL::SigSpec()
+ );
unassigned_cells.erase(cell);
expand_queue.insert(cell);
@@ -1979,7 +2131,7 @@ struct AbcPass : public Pass {
expand_queue.swap(next_expand_queue);
}
- clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec());
+ clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec(), true, RTLIL::SigSpec(), true, RTLIL::SigSpec());
for (auto cell : unassigned_cells) {
assigned_cells[key].push_back(cell);
assigned_cells_reverse[cell] = key;
@@ -1987,16 +2139,22 @@ struct AbcPass : public Pass {
log_header(design, "Summary of detected clock domains:\n");
for (auto &it : assigned_cells)
- log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second),
+ log(" %d cells in clk=%s%s, en=%s%s, arst=%s%s, srst=%s%s\n", GetSize(it.second),
std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
- std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)));
+ std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)),
+ std::get<4>(it.first) ? "" : "!", log_signal(std::get<5>(it.first)),
+ std::get<6>(it.first) ? "" : "!", log_signal(std::get<7>(it.first)));
for (auto &it : assigned_cells) {
clk_polarity = std::get<0>(it.first);
clk_sig = assign_map(std::get<1>(it.first));
en_polarity = std::get<2>(it.first);
en_sig = assign_map(std::get<3>(it.first));
- abc_module(design, mod, script_file, exe_file, liberty_files, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
+ arst_polarity = std::get<4>(it.first);
+ arst_sig = assign_map(std::get<5>(it.first));
+ srst_polarity = std::get<6>(it.first);
+ srst_sig = assign_map(std::get<7>(it.first));
+ abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress);
assign_map.set(mod);
}
diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc
index 1f00fc3e7..fe0802d70 100644
--- a/passes/techmap/abc9.cc
+++ b/passes/techmap/abc9.cc
@@ -74,12 +74,18 @@ struct Abc9Pass : public ScriptPass
/* Comm3 */ "&synch2 -K 6 -C 500; &if -m "/*"-E 5"*/" {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save;"\
/* Comm2 */ "&dch -C 500; &if -m {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save; "\
"&load";
- // Based on ABC's &flow3
+ // Based on ABC's &flow3 -m
RTLIL::constpad["abc9.script.flow3"] = "+&scorr; &sweep;" \
"&if {C} {W} {D}; &save; &st; &syn2; &if {C} {W} {D} {R} -v; &save; &load;"\
"&st; &if {C} -g -K 6; &dch -f; &if {C} {W} {D} {R} -v; &save; &load;"\
"&st; &if {C} -g -K 6; &synch2; &if {C} {W} {D} {R} -v; &save; &load;"\
"&mfs";
+ // As above, but with &mfs calls as in the original &flow3
+ RTLIL::constpad["abc9.script.flow3mfs"] = "+&scorr; &sweep;" \
+ "&if {C} {W} {D}; &save; &st; &syn2; &if {C} {W} {D} {R} -v; &save; &load;"\
+ "&st; &if {C} -g -K 6; &dch -f; &if {C} {W} {D} {R} -v; &mfs; &save; &load;"\
+ "&st; &if {C} -g -K 6; &synch2; &if {C} {W} {D} {R} -v; &mfs; &save; &load;"\
+ "&mfs";
}
void help() override
{
diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc
index 7a6959971..acafb0b65 100644
--- a/passes/techmap/abc9_ops.cc
+++ b/passes/techmap/abc9_ops.cc
@@ -155,6 +155,9 @@ void prep_hier(RTLIL::Design *design, bool dff_mode)
r.first->second = new Design;
Design *unmap_design = r.first->second;
+ // Keep track of derived versions of modules that we haven't used, to prevent these being used for unwanted techmaps later on.
+ pool<IdString> unused_derived;
+
for (auto module : design->selected_modules())
for (auto cell : module->cells()) {
auto inst_module = design->module(cell->type);
@@ -167,12 +170,9 @@ void prep_hier(RTLIL::Design *design, bool dff_mode)
derived_module = inst_module;
}
else {
- // Check potential for any one of those three
- // (since its value may depend on a parameter, but not its existence)
- if (!inst_module->has_attribute(ID::abc9_flop) && !inst_module->has_attribute(ID::abc9_box) && !inst_module->get_bool_attribute(ID::abc9_bypass))
- continue;
derived_type = inst_module->derive(design, cell->parameters);
derived_module = design->module(derived_type);
+ unused_derived.insert(derived_type);
}
if (derived_module->get_bool_attribute(ID::abc9_flop)) {
@@ -180,13 +180,23 @@ void prep_hier(RTLIL::Design *design, bool dff_mode)
continue;
}
else {
- if (!derived_module->get_bool_attribute(ID::abc9_box) && !derived_module->get_bool_attribute(ID::abc9_bypass)) {
+ bool has_timing = false;
+ for (auto derived_cell : derived_module->cells()) {
+ if (derived_cell->type.in(ID($specify2), ID($specify3), ID($specrule))) {
+ // If the module contains timing; then we potentially care about deriving its content too,
+ // as timings (or associated port widths) could be dependent on parameters.
+ has_timing = true;
+ break;
+ }
+ }
+ if (!derived_module->get_bool_attribute(ID::abc9_box) && !derived_module->get_bool_attribute(ID::abc9_bypass) && !has_timing) {
if (unmap_design->module(derived_type)) {
// If derived_type is present in unmap_design, it means that it was processed previously, but found to be incompatible -- e.g. if
// it contained a non-zero initial state. In this case, continue to replace the cell type/parameters so that it has the same properties
// as a compatible type, yet will be safely unmapped later
cell->type = derived_type;
cell->parameters.clear();
+ unused_derived.erase(derived_type);
}
continue;
}
@@ -245,7 +255,11 @@ void prep_hier(RTLIL::Design *design, bool dff_mode)
cell->type = derived_type;
cell->parameters.clear();
+ unused_derived.erase(derived_type);
}
+ for (auto unused : unused_derived) {
+ design->remove(design->module(unused));
+ }
}
void prep_bypass(RTLIL::Design *design)
@@ -648,40 +662,38 @@ void prep_delays(RTLIL::Design *design, bool dff_mode)
auto inst_module = design->module(cell->type);
log_assert(inst_module);
- auto &t = timing.at(cell->type).required;
- for (auto &conn : cell->connections_) {
- auto port_wire = inst_module->wire(conn.first);
+ for (auto &i : timing.at(cell->type).required) {
+ auto port_wire = inst_module->wire(i.first.name);
if (!port_wire)
log_error("Port %s in cell %s (type %s) from module %s does not actually exist",
- log_id(conn.first), log_id(cell), log_id(cell->type), log_id(module));
- if (!port_wire->port_input)
- continue;
- if (conn.second.is_fully_const())
+ log_id(i.first.name), log_id(cell), log_id(cell->type), log_id(module));
+ log_assert(port_wire->port_input);
+
+ auto d = i.second.first;
+ if (d == 0)
continue;
- SigSpec O = module->addWire(NEW_ID, GetSize(conn.second));
- for (int i = 0; i < GetSize(conn.second); i++) {
- auto d = t.at(TimingInfo::NameBit(conn.first,i), 0);
- if (d == 0)
- continue;
+ auto offset = i.first.offset;
+ auto O = module->addWire(NEW_ID);
+ auto rhs = cell->getPort(i.first.name);
#ifndef NDEBUG
- if (ys_debug(1)) {
- static std::set<std::tuple<IdString,IdString,int>> seen;
- if (seen.emplace(cell->type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n",
- log_id(cell->type), log_id(conn.first), i, d);
- }
+ if (ys_debug(1)) {
+ static pool<std::pair<IdString,TimingInfo::NameBit>> seen;
+ if (seen.emplace(cell->type, i.first).second) log("%s.%s[%d] abc9_required = %d\n",
+ log_id(cell->type), log_id(i.first.name), offset, d);
+ }
#endif
- auto r = box_cache.insert(d);
- if (r.second) {
- r.first->second = delay_module->derive(design, {{ID::DELAY, d}});
- log_assert(r.first->second.begins_with("$paramod$__ABC9_DELAY\\DELAY="));
- }
- auto box = module->addCell(NEW_ID, r.first->second);
- box->setPort(ID::I, conn.second[i]);
- box->setPort(ID::O, O[i]);
- conn.second[i] = O[i];
+ auto r = box_cache.insert(d);
+ if (r.second) {
+ r.first->second = delay_module->derive(design, {{ID::DELAY, d}});
+ log_assert(r.first->second.begins_with("$paramod$__ABC9_DELAY\\DELAY="));
}
+ auto box = module->addCell(NEW_ID, r.first->second);
+ box->setPort(ID::I, rhs[offset]);
+ box->setPort(ID::O, O);
+ rhs[offset] = O;
+ cell->setPort(i.first.name, rhs);
}
}
}
@@ -1006,16 +1018,16 @@ void prep_box(RTLIL::Design *design)
log_assert(GetSize(wire) == 1);
auto it = t.find(TimingInfo::NameBit(port_name,0));
if (it == t.end())
- // Assume no connectivity if no setup time
- ss << "-";
+ // Assume that no setup time means zero
+ ss << 0;
else {
- ss << it->second;
+ ss << it->second.first;
#ifndef NDEBUG
if (ys_debug(1)) {
static std::set<std::pair<IdString,IdString>> seen;
if (seen.emplace(module->name, port_name).second) log("%s.%s abc9_required = %d\n", log_id(module),
- log_id(port_name), it->second);
+ log_id(port_name), it->second.first);
}
#endif
}
diff --git a/passes/techmap/bmuxmap.cc b/passes/techmap/bmuxmap.cc
new file mode 100644
index 000000000..03673c278
--- /dev/null
+++ b/passes/techmap/bmuxmap.cc
@@ -0,0 +1,76 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2022 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"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct BmuxmapPass : public Pass {
+ BmuxmapPass() : Pass("bmuxmap", "transform $bmux cells to trees of $mux cells") { }
+ void help() override
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" bmuxmap [selection]\n");
+ log("\n");
+ log("This pass transforms $bmux cells to trees of $mux cells.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
+ {
+ log_header(design, "Executing BMUXMAP pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type != ID($bmux))
+ continue;
+
+ SigSpec sel = cell->getPort(ID::S);
+ SigSpec data = cell->getPort(ID::A);
+ int width = GetSize(cell->getPort(ID::Y));
+
+ for (int idx = 0; idx < GetSize(sel); idx++) {
+ SigSpec new_data = module->addWire(NEW_ID, GetSize(data)/2);
+ for (int i = 0; i < GetSize(new_data); i += width) {
+ RTLIL::Cell *mux = module->addMux(NEW_ID,
+ data.extract(i*2, width),
+ data.extract(i*2+width, width),
+ sel[idx],
+ new_data.extract(i, width));
+ mux->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+ }
+ data = new_data;
+ }
+
+ module->connect(cell->getPort(ID::Y), data);
+ module->remove(cell);
+ }
+ }
+} BmuxmapPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/demuxmap.cc b/passes/techmap/demuxmap.cc
new file mode 100644
index 000000000..292b18bad
--- /dev/null
+++ b/passes/techmap/demuxmap.cc
@@ -0,0 +1,80 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2022 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"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct DemuxmapPass : public Pass {
+ DemuxmapPass() : Pass("demuxmap", "transform $demux cells to $eq + $mux cells") { }
+ void help() override
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" demuxmap [selection]\n");
+ log("\n");
+ log("This pass transforms $demux cells to a bunch of equality comparisons.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
+ {
+ log_header(design, "Executing DEMUXMAP pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type != ID($demux))
+ continue;
+
+ SigSpec sel = cell->getPort(ID::S);
+ SigSpec data = cell->getPort(ID::A);
+ SigSpec out = cell->getPort(ID::Y);
+ int width = GetSize(cell->getPort(ID::A));
+
+ for (int i = 0; i < 1 << GetSize(sel); i++) {
+ if (width == 1 && data == State::S1) {
+ RTLIL::Cell *eq_cell = module->addEq(NEW_ID, sel, Const(i, GetSize(sel)), out[i]);
+ eq_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+ } else {
+ Wire *eq = module->addWire(NEW_ID);
+ RTLIL::Cell *eq_cell = module->addEq(NEW_ID, sel, Const(i, GetSize(sel)), eq);
+ eq_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+ RTLIL::Cell *mux = module->addMux(NEW_ID,
+ Const(State::S0, width),
+ data,
+ eq,
+ out.extract(i*width, width));
+ mux->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+ }
+ }
+
+ module->remove(cell);
+ }
+ }
+} DemuxmapPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/dfflegalize.cc b/passes/techmap/dfflegalize.cc
index c1e7e557d..1d99caa3a 100644
--- a/passes/techmap/dfflegalize.cc
+++ b/passes/techmap/dfflegalize.cc
@@ -20,6 +20,7 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/ffinit.h"
+#include "kernel/ff.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -27,38 +28,42 @@ PRIVATE_NAMESPACE_BEGIN
enum FfType {
FF_DFF,
FF_DFFE,
- FF_ADFF0,
- FF_ADFF1,
- FF_ADFFE0,
- FF_ADFFE1,
+ FF_ADFF,
+ FF_ADFFE,
+ FF_ALDFF,
+ FF_ALDFFE,
FF_DFFSR,
FF_DFFSRE,
- FF_SDFF0,
- FF_SDFF1,
- FF_SDFFE0,
- FF_SDFFE1,
- FF_SDFFCE0,
- FF_SDFFCE1,
+ FF_SDFF,
+ FF_SDFFE,
+ FF_SDFFCE,
+ FF_RLATCH,
FF_SR,
FF_DLATCH,
- FF_ADLATCH0,
- FF_ADLATCH1,
+ FF_ADLATCH,
FF_DLATCHSR,
NUM_FFTYPES,
};
enum FfNeg {
- NEG_R = 0x1,
- NEG_S = 0x2,
- NEG_E = 0x4,
- NEG_C = 0x8,
- NUM_NEG = 0x10,
+ NEG_CE = 0x1,
+ NEG_R = 0x2,
+ NEG_S = 0x4,
+ NEG_L = 0x8,
+ NEG_C = 0x10,
+ NUM_NEG = 0x20,
};
enum FfInit {
INIT_X = 0x1,
INIT_0 = 0x2,
INIT_1 = 0x4,
+ INIT_X_R0 = 0x10,
+ INIT_0_R0 = 0x20,
+ INIT_1_R0 = 0x40,
+ INIT_X_R1 = 0x100,
+ INIT_0_R1 = 0x200,
+ INIT_1_R1 = 0x400,
};
struct DffLegalizePass : public Pass {
@@ -101,6 +106,8 @@ struct DffLegalizePass : public Pass {
log("- $_DFFE_[NP][NP]_\n");
log("- $_DFF_[NP][NP][01]_\n");
log("- $_DFFE_[NP][NP][01][NP]_\n");
+ log("- $_ALDFF_[NP][NP]_\n");
+ log("- $_ALDFFE_[NP][NP][NP]_\n");
log("- $_DFFSR_[NP][NP][NP]_\n");
log("- $_DFFSRE_[NP][NP][NP][NP]_\n");
log("- $_SDFF_[NP][NP][01]_\n");
@@ -151,18 +158,30 @@ struct DffLegalizePass : public Pass {
int supported_cells[NUM_FFTYPES];
// Aggregated for all *dff* cells.
int supported_dff;
+ // Aggregated for all *dffe* cells.
+ int supported_dffe;
// Aggregated for all dffsr* cells.
int supported_dffsr;
- // Aggregated for all adff* cells.
- int supported_adff0;
- int supported_adff1;
+ // Aggregated for all aldff cells.
+ int supported_aldff;
+ // Aggregated for all aldffe cells.
+ int supported_aldffe;
+ // Aggregated for all adff* cells and trivial emulations.
+ int supported_adff;
+ // Aggregated for all adffe* cells and trivial emulations.
+ int supported_adffe;
// Aggregated for all sdff* cells.
- int supported_sdff0;
- int supported_sdff1;
+ int supported_sdff;
// Aggregated for all ways to obtain a SR latch.
int supported_sr;
+ int supported_sr_plain;
// Aggregated for all *dlatch* cells.
int supported_dlatch;
+ int supported_dlatch_plain;
+ // Aggregated for all ways to obtain an R latch.
+ int supported_rlatch;
+ // Aggregated for all adlatch cells and trivial emulations.
+ int supported_adlatch;
int mince;
int minsrst;
@@ -179,736 +198,794 @@ struct DffLegalizePass : public Pass {
res |= INIT_1;
if (mask & INIT_1)
res |= INIT_0;
+ if (mask & INIT_X_R0)
+ res |= INIT_X_R1;
+ if (mask & INIT_0_R0)
+ res |= INIT_1_R1;
+ if (mask & INIT_1_R0)
+ res |= INIT_0_R1;
+ if (mask & INIT_X_R1)
+ res |= INIT_X_R0;
+ if (mask & INIT_0_R1)
+ res |= INIT_1_R0;
+ if (mask & INIT_1_R1)
+ res |= INIT_0_R0;
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;
+ int get_ff_type(const FfData &ff) {
+ if (ff.has_clk) {
+ if (ff.has_sr) {
+ return ff.has_ce ? FF_DFFSRE : FF_DFFSR;
+ } else if (ff.has_arst) {
+ return ff.has_ce ? FF_ADFFE : FF_ADFF;
+ } else if (ff.has_aload) {
+ return ff.has_ce ? FF_ALDFFE : FF_ALDFF;
+ } else if (ff.has_srst) {
+ if (ff.has_ce)
+ return ff.ce_over_srst ? FF_SDFFCE : FF_SDFFE;
+ else
+ return FF_SDFF;
+ } else {
+ return ff.has_ce ? FF_DFFE : FF_DFF;
+ }
} 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;
+ if (ff.has_aload) {
+ if (ff.has_sr)
+ return FF_DLATCHSR;
+ else if (ff.has_arst)
+ return FF_ADLATCH;
+ else
+ return FF_DLATCH;
+ } else {
+ if (ff.has_sr) {
+ return FF_SR;
+ } else if (ff.has_arst) {
+ return FF_RLATCH;
+ } else {
+ log_assert(0);
+ return 0;
+ }
+ }
+ }
+ }
+
+ int get_initmask(FfData &ff) {
+ int res = 0;
+ if (ff.val_init[0] == State::S0)
+ res = INIT_0;
+ else if (ff.val_init[0] == State::S1)
+ res = INIT_1;
+ else
+ res = INIT_X;
+ if (ff.has_arst) {
+ if (ff.val_arst[0] == State::S0)
+ res <<= 4;
+ else if (ff.val_arst[0] == State::S1)
+ res <<= 8;
+ } else if (ff.has_srst) {
+ if (ff.val_srst[0] == State::S0)
+ res <<= 4;
+ else if (ff.val_srst[0] == State::S1)
+ res <<= 8;
+ }
+ return res;
+ }
+
+ void fail_ff(const FfData &ff, const char *reason) {
+ log_error("FF %s.%s (type %s) cannot be legalized: %s\n", log_id(ff.module->name), log_id(ff.cell->name), log_id(ff.cell->type), reason);
+ }
+
+ bool try_flip(FfData &ff, int supported_mask) {
+ int initmask = get_initmask(ff);
+ if (supported_mask & initmask)
+ return true;
+ if (supported_mask & flip_initmask(initmask)) {
+ ff.flip_bits({0});
+ return true;
}
+ return false;
+ }
- 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;
+ void emulate_split_init_arst(FfData &ff) {
+ ff.remove();
- 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;
+ FfData ff_dff(ff.module, &initvals, NEW_ID);
+ ff_dff.width = ff.width;
+ ff_dff.has_aload = ff.has_aload;
+ ff_dff.sig_aload = ff.sig_aload;
+ ff_dff.pol_aload = ff.pol_aload;
+ ff_dff.sig_ad = ff.sig_ad;
+ ff_dff.has_clk = ff.has_clk;
+ ff_dff.sig_clk = ff.sig_clk;
+ ff_dff.pol_clk = ff.pol_clk;
+ ff_dff.sig_d = ff.sig_d;
+ ff_dff.has_ce = ff.has_ce;
+ ff_dff.sig_ce = ff.sig_ce;
+ ff_dff.pol_ce = ff.pol_ce;
+ ff_dff.sig_q = ff.module->addWire(NEW_ID, ff.width);
+ ff_dff.val_init = ff.val_init;
+ ff_dff.is_fine = ff.is_fine;
- while (!(supported_cells[ff_type] & initmask) || kill_ce || kill_srst) {
- // Well, cell is not directly supported. Decide how to deal with it.
+ FfData ff_adff(ff.module, &initvals, NEW_ID);
+ ff_adff.width = ff.width;
+ ff_adff.has_aload = ff.has_aload;
+ ff_adff.sig_aload = ff.sig_aload;
+ ff_adff.pol_aload = ff.pol_aload;
+ ff_adff.sig_ad = ff.sig_ad;
+ ff_adff.has_clk = ff.has_clk;
+ ff_adff.sig_clk = ff.sig_clk;
+ ff_adff.pol_clk = ff.pol_clk;
+ ff_adff.sig_d = ff.sig_d;
+ ff_adff.has_ce = ff.has_ce;
+ ff_adff.sig_ce = ff.sig_ce;
+ ff_adff.pol_ce = ff.pol_ce;
+ ff_adff.sig_q = ff.module->addWire(NEW_ID, ff.width);
+ ff_adff.val_init = Const(State::Sx, ff.width);
+ ff_adff.has_arst = true;
+ ff_adff.sig_arst = ff.sig_arst;
+ ff_adff.pol_arst = ff.pol_arst;
+ ff_adff.val_arst = ff.val_arst;
+ ff_adff.is_fine = ff.is_fine;
- 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;
- }
+ FfData ff_sel(ff.module, &initvals, NEW_ID);
+ ff_sel.width = 1;
+ ff_sel.sig_q = ff.module->addWire(NEW_ID);
+ ff_sel.has_arst = true;
+ ff_sel.sig_arst = ff.sig_arst;
+ ff_sel.pol_arst = ff.pol_arst;
+ ff_sel.val_arst = State::S1;
+ ff_sel.val_init = State::S0;
+ ff_sel.is_fine = ff.is_fine;
- // 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;
- }
+ if (ff.is_fine)
+ ff.module->addMuxGate(NEW_ID, ff_dff.sig_q, ff_adff.sig_q, ff_sel.sig_q, ff.sig_q);
+ else
+ ff.module->addMux(NEW_ID, ff_dff.sig_q, ff_adff.sig_q, ff_sel.sig_q, ff.sig_q);
+
+ legalize_ff(ff_dff);
+ legalize_ff(ff_adff);
+ legalize_ff(ff_sel);
+ }
- // 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]);
+ void emulate_split_set_clr(FfData &ff) {
+ // No native DFFSR. However, if we can conjure
+ // a SR latch and ADFF, it can still be emulated.
+ int initmask = get_initmask(ff);
+ int flipmask = flip_initmask(initmask);
+ bool init_clr = true;
+ bool init_set = true;
+ State initsel = State::Sx;
+ int supported_arst = ff.has_clk ? supported_adff : supported_adlatch;
+ bool init_clr_ok = (supported_arst & initmask << 4) || (supported_arst & flipmask << 8);
+ bool init_set_ok = (supported_arst & initmask << 8) || (supported_arst & flipmask << 4);
+ if (init_clr_ok && init_set_ok && supported_sr) {
+ // OK
+ } else if (init_clr_ok && (supported_sr & INIT_0)) {
+ init_set = false;
+ initsel = State::S0;
+ } else if (init_set_ok && (supported_sr & INIT_1)) {
+ init_clr = false;
+ initsel = State::S1;
+ } else if (init_clr_ok && (supported_sr & INIT_1)) {
+ init_set = false;
+ initsel = State::S0;
+ } else if (init_set_ok && (supported_sr & INIT_0)) {
+ init_clr = false;
+ initsel = State::S1;
+ } else {
+ if (ff.has_clk) {
+ if (!supported_dffsr)
+ fail_ff(ff, "dffs with async set and reset are not supported");
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;
- }
+ fail_ff(ff, "initialized dffs with async set and reset are not supported");
+ } else {
+ if (!supported_cells[FF_DLATCHSR])
+ fail_ff(ff, "dlatch with async set and reset are not supported");
+ else
+ fail_ff(ff, "initialized dlatch with async set and reset are not supported");
+ }
+ }
- 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 (ff.has_ce && !supported_cells[FF_ADFFE])
+ ff.unmap_ce();
- // 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 async set + reset with several FFs and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name));
- 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;
- }
+ log_assert(ff.width == 1);
+ ff.remove();
- // 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;
- }
+ FfData ff_clr(ff.module, &initvals, NEW_ID);
+ ff_clr.width = ff.width;
+ ff_clr.has_aload = ff.has_aload;
+ ff_clr.sig_aload = ff.sig_aload;
+ ff_clr.pol_aload = ff.pol_aload;
+ ff_clr.sig_ad = ff.sig_ad;
+ ff_clr.has_clk = ff.has_clk;
+ ff_clr.sig_clk = ff.sig_clk;
+ ff_clr.pol_clk = ff.pol_clk;
+ ff_clr.sig_d = ff.sig_d;
+ ff_clr.has_ce = ff.has_ce;
+ ff_clr.sig_ce = ff.sig_ce;
+ ff_clr.pol_ce = ff.pol_ce;
+ ff_clr.has_arst = true;
+ ff_clr.sig_arst = ff.sig_clr;
+ ff_clr.pol_arst = ff.pol_clr;
+ ff_clr.val_arst = Const(State::S0, ff.width);
+ ff_clr.sig_q = ff.module->addWire(NEW_ID, ff.width);
+ ff_clr.val_init = init_clr ? ff.val_init : Const(State::Sx, ff.width);
+ ff_clr.is_fine = ff.is_fine;
- 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);
+ FfData ff_set(ff.module, &initvals, NEW_ID);
+ ff_set.width = ff.width;
+ ff_set.has_aload = ff.has_aload;
+ ff_set.sig_aload = ff.sig_aload;
+ ff_set.pol_aload = ff.pol_aload;
+ ff_set.sig_ad = ff.sig_ad;
+ ff_set.has_clk = ff.has_clk;
+ ff_set.sig_clk = ff.sig_clk;
+ ff_set.pol_clk = ff.pol_clk;
+ ff_set.sig_d = ff.sig_d;
+ ff_set.has_ce = ff.has_ce;
+ ff_set.sig_ce = ff.sig_ce;
+ ff_set.pol_ce = ff.pol_ce;
+ ff_set.has_arst = true;
+ ff_set.sig_arst = ff.sig_set;
+ ff_set.pol_arst = ff.pol_set;
+ ff_set.val_arst = Const(State::S1, ff.width);
+ ff_set.sig_q = ff.module->addWire(NEW_ID, ff.width);
+ ff_set.val_init = init_set ? ff.val_init : Const(State::Sx, ff.width);
+ ff_set.is_fine = ff.is_fine;
+
+ FfData ff_sel(ff.module, &initvals, NEW_ID);
+ ff_sel.width = ff.width;
+ ff_sel.has_sr = true;
+ ff_sel.pol_clr = ff.pol_clr;
+ ff_sel.pol_set = ff.pol_set;
+ ff_sel.sig_clr = ff.sig_clr;
+ ff_sel.sig_set = ff.sig_set;
+ ff_sel.sig_q = ff.module->addWire(NEW_ID, ff.width);
+ ff_sel.val_init = Const(initsel, ff.width);
+ ff_sel.is_fine = ff.is_fine;
+
+ if (!ff.is_fine)
+ ff.module->addMux(NEW_ID, ff_clr.sig_q, ff_set.sig_q, ff_sel.sig_q, ff.sig_q);
+ else
+ ff.module->addMuxGate(NEW_ID, ff_clr.sig_q, ff_set.sig_q, ff_sel.sig_q, ff.sig_q);
+
+ legalize_ff(ff_clr);
+ legalize_ff(ff_set);
+ legalize_ff(ff_sel);
+ }
+
+ void legalize_dff(FfData &ff) {
+ if (!try_flip(ff, supported_dff)) {
+ if (!supported_dff)
+ fail_ff(ff, "D flip-flops are not supported");
+ else
+ fail_ff(ff, "initialized D flip-flops are not supported");
+ }
+
+ int initmask = get_initmask(ff);
+ // Some DFF is supported with this init val. Just pick a type.
+ if (ff.has_ce && !(supported_dffe & initmask)) {
+ ff.unmap_ce();
+ }
+
+ if (!ff.has_ce) {
+ if (supported_cells[FF_DFF] & initmask) {
+ legalize_finish(ff);
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;
- }
+ }
+ // Try adding a set or reset pin.
+ if (supported_cells[FF_SDFF] & initmask) {
+ ff.add_dummy_srst();
+ legalize_finish(ff);
+ return;
+ }
+ if (supported_cells[FF_ADFF] & initmask) {
+ ff.add_dummy_arst();
+ legalize_finish(ff);
+ return;
+ }
+ // Try adding async load.
+ if (supported_cells[FF_ALDFF] & initmask) {
+ ff.add_dummy_aload();
+ legalize_finish(ff);
+ return;
+ }
+ // Try adding both.
+ if (supported_cells[FF_DFFSR] & initmask) {
+ ff.add_dummy_sr();
+ legalize_finish(ff);
+ return;
+ }
+ // Nope. Will need to add enable and go the DFFE route.
+ ff.add_dummy_ce();
+ }
+ if (supported_cells[FF_DFFE] & initmask) {
+ legalize_finish(ff);
+ return;
+ }
+ // Try adding a set or reset pin.
+ if (supported_cells[FF_SDFFCE] & initmask) {
+ ff.add_dummy_srst();
+ ff.ce_over_srst = true;
+ legalize_finish(ff);
+ return;
+ }
+ if (supported_cells[FF_SDFFE] & initmask) {
+ ff.add_dummy_srst();
+ legalize_finish(ff);
+ return;
+ }
+ if (supported_cells[FF_ADFFE] & initmask) {
+ ff.add_dummy_arst();
+ legalize_finish(ff);
+ return;
+ }
+ if (supported_cells[FF_ALDFFE] & initmask) {
+ ff.add_dummy_aload();
+ legalize_finish(ff);
+ return;
+ }
+ // Try adding both.
+ if (supported_cells[FF_DFFSRE] & initmask) {
+ ff.add_dummy_sr();
+ legalize_finish(ff);
+ return;
+ }
+ log_assert(0);
+ }
- if (!supported_dlatch)
- reason = "dlatch are not supported";
- else
- reason = "initialized dlatch are not supported";
- goto error;
- }
+ void legalize_sdffce(FfData &ff) {
+ if (!try_flip(ff, supported_cells[FF_SDFFCE] | supported_cells[FF_SDFFE])) {
+ ff.unmap_srst();
+ legalize_dff(ff);
+ return;
+ }
- // 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;
- }
+ int initmask = get_initmask(ff);
+ if (supported_cells[FF_SDFFCE] & initmask) {
+ // OK
+ } else if (supported_cells[FF_SDFFE] & initmask) {
+ ff.convert_ce_over_srst(false);
+ } else {
+ log_assert(0);
+ }
+ legalize_finish(ff);
+ }
+
+ void legalize_sdff(FfData &ff) {
+ if (!try_flip(ff, supported_sdff)) {
+ ff.unmap_srst();
+ legalize_dff(ff);
+ return;
+ }
+
+ int initmask = get_initmask(ff);
+ if (!ff.has_ce) {
+ if (supported_cells[FF_SDFF] & initmask) {
+ // OK
+ } else if (supported_cells[FF_SDFFE] & initmask) {
+ ff.add_dummy_ce();
+ } else if (supported_cells[FF_SDFFCE] & initmask) {
+ ff.add_dummy_ce();
+ ff.ce_over_srst = true;
+ } else {
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;
- }
+ }
+ } else {
+ log_assert(!ff.ce_over_srst);
+ if (supported_cells[FF_SDFFE] & initmask) {
+ // OK
+ } else if (supported_cells[FF_SDFFCE] & initmask) {
+ ff.convert_ce_over_srst(true);
+ } else if (supported_cells[FF_SDFF] & initmask) {
+ ff.unmap_ce();
+ } else {
+ log_assert(0);
+ }
+ }
+ legalize_finish(ff);
+ }
- 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;
- }
+ void legalize_adff(FfData &ff) {
+ if (!try_flip(ff, supported_adff)) {
+ if (!supported_adff)
+ fail_ff(ff, "dffs with async set or reset are not supported");
+ if (!(supported_dff & (INIT_0 | INIT_1)))
+ fail_ff(ff, "initialized dffs are not supported");
- 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);
+ // 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_rlatch) & (INIT_0_R1 | INIT_1_R0)))
+ fail_ff(ff, "unsupported initial value and async reset value combination");
+
+ // If we have to unmap enable anyway, do it before breakdown.
+ if (ff.has_ce && !supported_cells[FF_ADFFE])
+ ff.unmap_ce();
+
+ if (ff.cell)
+ log_warning("Emulating mismatched async reset and init with several FFs and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name));
+ emulate_split_init_arst(ff);
+ return;
+ }
+
+ int initmask = get_initmask(ff);
+ if (ff.has_ce && !(supported_adffe & initmask)) {
+ ff.unmap_ce();
+ }
+
+ if (!ff.has_ce) {
+ if (supported_cells[FF_ADFF] & initmask) {
+ legalize_finish(ff);
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;
- }
+ }
+ // Try converting to async load.
+ if (supported_cells[FF_ALDFF] & initmask) {
+ ff.arst_to_aload();
+ legalize_finish(ff);
+ return;
+ }
+ // Try convertint to SR.
+ if (supported_cells[FF_DFFSR] & initmask) {
+ ff.arst_to_sr();
+ legalize_finish(ff);
+ return;
+ }
+ ff.add_dummy_ce();
+ }
+ if (supported_cells[FF_ADFFE] & initmask) {
+ legalize_finish(ff);
+ return;
+ }
+ // Try converting to async load.
+ if (supported_cells[FF_ALDFFE] & initmask) {
+ ff.arst_to_aload();
+ legalize_finish(ff);
+ return;
+ }
+ // Try convertint to SR.
+ if (supported_cells[FF_DFFSRE] & initmask) {
+ ff.arst_to_sr();
+ legalize_finish(ff);
+ return;
+ }
+ log_assert(0);
+ }
+
+ void legalize_aldff(FfData &ff) {
+ if (!try_flip(ff, supported_aldff)) {
+ ff.aload_to_sr();
+ emulate_split_set_clr(ff);
+ return;
+ }
+
+ int initmask = get_initmask(ff);
+ if (ff.has_ce && !(supported_aldffe & initmask)) {
+ ff.unmap_ce();
+ }
- 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);
+ if (!ff.has_ce) {
+ if (supported_cells[FF_ALDFF] & initmask) {
+ legalize_finish(ff);
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 (supported_cells[FF_DFFSR] & initmask) {
+ ff.aload_to_sr();
+ legalize_finish(ff);
+ return;
+ }
+ ff.add_dummy_ce();
+ }
+ if (supported_cells[FF_ALDFFE] & initmask) {
+ legalize_finish(ff);
+ return;
+ }
+ if (supported_cells[FF_DFFSRE] & initmask) {
+ ff.aload_to_sr();
+ legalize_finish(ff);
+ return;
+ }
+ log_assert(0);
+ }
- 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;
- }
+ void legalize_dffsr(FfData &ff) {
+ if (!try_flip(ff, supported_dffsr)) {
+ emulate_split_set_clr(ff);
+ return;
+ }
+
+ int initmask = get_initmask(ff);
+ if (ff.has_ce && !(supported_cells[FF_DFFSRE] & initmask)) {
+ ff.unmap_ce();
+ }
+
+ if (!ff.has_ce) {
+ if (supported_cells[FF_DFFSR] & initmask) {
+ legalize_finish(ff);
+ return;
+ }
+ ff.add_dummy_ce();
+ }
+
+ log_assert(supported_cells[FF_DFFSRE] & initmask);
+ legalize_finish(ff);
+ }
+
+ void legalize_dlatch(FfData &ff) {
+ if (!try_flip(ff, supported_dlatch)) {
+ if (!supported_dlatch)
+ fail_ff(ff, "D latches are not supported");
+ else
+ fail_ff(ff, "initialized D latches are not supported");
+ }
+
+ int initmask = get_initmask(ff);
+ // Some DLATCH is supported with this init val. Just pick a type.
+ if (supported_cells[FF_DLATCH] & initmask) {
+ legalize_finish(ff);
+ } else if (supported_cells[FF_ADLATCH] & initmask) {
+ ff.add_dummy_arst();
+ legalize_finish(ff);
+ } else if (supported_cells[FF_DLATCHSR] & initmask) {
+ ff.add_dummy_sr();
+ legalize_finish(ff);
+ } else if (supported_cells[FF_ALDFF] & initmask) {
+ ff.add_dummy_clk();
+ legalize_finish(ff);
+ } else if (supported_cells[FF_ALDFFE] & initmask) {
+ ff.add_dummy_clk();
+ ff.add_dummy_ce();
+ legalize_finish(ff);
+ } else if (supported_sr & initmask) {
+ ff.aload_to_sr();
+ legalize_sr(ff);
+ } else {
+ log_assert(0);
+ }
+ }
+
+ void legalize_adlatch(FfData &ff) {
+ if (!try_flip(ff, supported_adlatch)) {
+ if (!supported_adlatch)
+ fail_ff(ff, "D latches with async set or reset are not supported");
+ if (!(supported_dlatch & (INIT_0 | INIT_1)))
+ fail_ff(ff, "initialized D latches are not supported");
+
+ // 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 adlatch + dlatch + dlatch + mux.
+
+ if (ff.cell)
+ log_warning("Emulating mismatched async reset and init with several latches and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name));
+ ff.remove();
+
+ emulate_split_init_arst(ff);
+ return;
+ }
+ int initmask = get_initmask(ff);
+ if (supported_cells[FF_ADLATCH] & initmask) {
+ // OK
+ } else if (supported_cells[FF_DLATCHSR] & initmask) {
+ ff.arst_to_sr();
+ } else {
+ log_assert(0);
+ }
+ legalize_finish(ff);
+ }
+
+ void legalize_dlatchsr(FfData &ff) {
+ if (!try_flip(ff, supported_cells[FF_DLATCHSR])) {
+ emulate_split_set_clr(ff);
+ return;
+ }
+ legalize_finish(ff);
+ }
+
+ void legalize_rlatch(FfData &ff) {
+ if (!try_flip(ff, supported_rlatch)) {
+ if (!supported_dlatch)
+ fail_ff(ff, "D latches are not supported");
+ else
+ fail_ff(ff, "initialized D latches are not supported");
+ }
+
+ int initmask = get_initmask(ff);
+ if (((supported_dlatch_plain & 7) * 0x111) & initmask) {
+ ff.arst_to_aload();
+ legalize_dlatch(ff);
+ } else if (supported_sr & initmask) {
+ ff.arst_to_sr();
+ legalize_sr(ff);
+ } else if (supported_adff & initmask) {
+ ff.add_dummy_clk();
+ legalize_adff(ff);
+ } else {
+ log_assert(0);
+ }
+ }
+
+ void legalize_sr(FfData &ff) {
+ if (!try_flip(ff, supported_sr)) {
+ if (!supported_sr)
+ fail_ff(ff, "sr latches are not supported");
+ else
+ fail_ff(ff, "initialized sr latches are not supported");
+ }
+ int initmask = get_initmask(ff);
+ if (supported_cells[FF_SR] & initmask) {
+ // OK
+ } else if (supported_cells[FF_DLATCHSR] & initmask) {
+ // Upgrade to DLATCHSR.
+ ff.add_dummy_aload();
+ } else if (supported_cells[FF_DFFSR] & initmask) {
+ // Upgrade to DFFSR.
+ ff.add_dummy_clk();
+ } else if (supported_cells[FF_DFFSRE] & initmask) {
+ // Upgrade to DFFSRE.
+ ff.add_dummy_clk();
+ ff.add_dummy_ce();
+ } else if (supported_cells[FF_ADLATCH] & (initmask << 4)) {
+ ff.has_sr = false;
+ ff.has_aload = true;
+ ff.has_arst = true;
+ ff.pol_arst = ff.pol_clr;
+ ff.sig_arst = ff.sig_clr;
+ ff.sig_aload = ff.sig_set;
+ ff.pol_aload = ff.pol_set;
+ ff.sig_ad = State::S1;
+ ff.val_arst = State::S0;
+ } else if (supported_cells[FF_ADLATCH] & (flip_initmask(initmask) << 8)) {
+ ff.has_sr = false;
+ ff.has_aload = true;
+ ff.has_arst = true;
+ ff.pol_arst = ff.pol_clr;
+ ff.sig_arst = ff.sig_clr;
+ ff.sig_aload = ff.sig_set;
+ ff.pol_aload = ff.pol_set;
+ ff.sig_ad = State::S0;
+ ff.val_arst = State::S1;
+ ff.remove_init();
+ Wire *new_q = ff.module->addWire(NEW_ID);
+ if (ff.is_fine)
+ ff.module->addNotGate(NEW_ID, new_q, ff.sig_q);
+ else
+ ff.module->addNot(NEW_ID, new_q, ff.sig_q);
+ ff.sig_q = new_q;
+ if (ff.val_init == State::S0)
+ ff.val_init = State::S1;
+ else if (ff.val_init == State::S1)
+ ff.val_init = State::S0;
+ } else {
+ log_assert(0);
+ }
+ legalize_finish(ff);
+ }
+
+ void fixup_reset_x(FfData &ff, int supported) {
+ for (int i = 0; i < ff.width; i++) {
+ int mask;
+ if (ff.val_init[i] == State::S0)
+ mask = INIT_0;
+ else if (ff.val_init[i] == State::S1)
+ mask = INIT_1;
+ else
+ mask = INIT_X;
+ if (ff.has_arst) {
+ if (ff.val_arst[i] == State::Sx) {
+ if (!(supported & (mask << 8)))
+ ff.val_arst[i] = State::S0;
+ if (!(supported & (mask << 4)))
+ ff.val_arst[i] = State::S1;
}
- // 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;
+ }
+ if (ff.has_srst) {
+ if (ff.val_srst[i] == State::Sx) {
+ if (!(supported & (mask << 8)))
+ ff.val_srst[i] = State::S0;
+ if (!(supported & (mask << 4)))
+ ff.val_srst[i] = State::S1;
}
+ }
+ }
+ }
- // 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]);
+ void legalize_ff(FfData &ff) {
+ if (ff.has_gclk)
+ return;
+
+ // TODO: consider supporting coarse as well.
+ if (!ff.is_fine)
+ return;
+
+ if (mince && ff.has_ce && ff.sig_ce[0].wire && ce_used[ff.sig_ce[0]] < mince)
+ ff.unmap_ce();
+ if (minsrst && ff.has_srst && ff.sig_srst[0].wire && srst_used[ff.sig_srst[0]] < minsrst)
+ ff.unmap_srst();
+
+ if (ff.has_clk) {
+ if (ff.has_sr) {
+ legalize_dffsr(ff);
+ } else if (ff.has_aload) {
+ legalize_aldff(ff);
+ } else if (ff.has_arst) {
+ legalize_adff(ff);
+ } else if (ff.has_srst) {
+ if (ff.has_ce && ff.ce_over_srst)
+ legalize_sdffce(ff);
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;
+ legalize_sdff(ff);
+ } else {
+ legalize_dff(ff);
+ }
+ } else if (ff.has_aload) {
+ if (ff.has_sr) {
+ legalize_dlatchsr(ff);
+ } else if (ff.has_arst) {
+ legalize_adlatch(ff);
+ } else {
+ legalize_dlatch(ff);
+ }
+ } else {
+ if (ff.has_sr) {
+ legalize_sr(ff);
+ } else if (ff.has_arst) {
+ legalize_rlatch(ff);
} else {
log_assert(0);
}
}
-cell_ok:
+ }
+
+ void flip_pol(FfData &ff, SigSpec &sig, bool &pol) {
+ if (sig == State::S0) {
+ sig = State::S1;
+ } else if (sig == State::S1) {
+ sig = State::S0;
+ } else if (ff.is_fine) {
+ sig = ff.module->NotGate(NEW_ID, sig);
+ } else {
+ sig = ff.module->Not(NEW_ID, sig);
+ }
+ pol = !pol;
+ }
+ void legalize_finish(FfData &ff) {
+ int ff_type = get_ff_type(ff);
+ int initmask = get_initmask(ff);
+ log_assert(supported_cells[ff_type] & initmask);
+ int ff_neg = 0;
+ if (ff.has_sr) {
+ if (!ff.pol_clr)
+ ff_neg |= NEG_R;
+ if (!ff.pol_set)
+ ff_neg |= NEG_S;
+ }
+ if (ff.has_arst) {
+ if (!ff.pol_arst)
+ ff_neg |= NEG_R;
+ }
+ if (ff.has_srst) {
+ if (!ff.pol_srst)
+ ff_neg |= NEG_R;
+ }
+ if (ff.has_aload) {
+ if (!ff.pol_aload)
+ ff_neg |= NEG_L;
+ }
+ if (ff.has_clk) {
+ if (!ff.pol_clk)
+ ff_neg |= NEG_C;
+ }
+ if (ff.has_ce) {
+ if (!ff.pol_ce)
+ ff_neg |= NEG_CE;
+ }
if (!(supported_cells_neg[ff_type][ff_neg] & initmask)) {
// Cell is supported, but not with those polarities.
// Will need to add some inverters.
@@ -921,182 +998,27 @@ cell_ok:
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_CE)
+ flip_pol(ff, ff.sig_ce, ff.pol_ce);
+ if (ff.has_sr) {
+ if (xneg & NEG_R)
+ flip_pol(ff, ff.sig_clr, ff.pol_clr);
+ if (xneg & NEG_S)
+ flip_pol(ff, ff.sig_set, ff.pol_set);
+ }
+ if (ff.has_arst && xneg & NEG_R)
+ flip_pol(ff, ff.sig_arst, ff.pol_arst);
+ if (ff.has_srst && xneg & NEG_R)
+ flip_pol(ff, ff.sig_srst, ff.pol_srst);
+ if (xneg & NEG_L)
+ flip_pol(ff, ff.sig_aload, ff.pol_aload);
if (xneg & NEG_C)
- sig_c = cell->module->NotGate(NEW_ID, sig_c[0]);
+ flip_pol(ff, ff.sig_clk, ff.pol_clk);
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);
+ fixup_reset_x(ff, supported_cells_neg[ff_type][ff_neg]);
+ ff.emit();
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
@@ -1118,79 +1040,83 @@ error:
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};
+ enum FfType ff_type;
char pol_c = 0;
- char pol_e = 0;
+ char pol_l = 0;
char pol_s = 0;
char pol_r = 0;
+ char pol_ce = 0;
char srval = 0;
if (celltype.substr(0, 5) == "$_SR_" && celltype.size() == 8 && celltype[7] == '_') {
- ff_type[0] = FF_SR;
+ ff_type = 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;
+ ff_type = FF_DFF;
pol_c = celltype[6];
} else if (celltype.substr(0, 7) == "$_DFFE_" && celltype.size() == 10 && celltype[9] == '_') {
- ff_type[0] = FF_DFFE;
+ ff_type = FF_DFFE;
pol_c = celltype[7];
- pol_e = celltype[8];
+ pol_ce = celltype[8];
} else if (celltype.substr(0, 6) == "$_DFF_" && celltype.size() == 10 && celltype[9] == '_') {
- ff_type[0] = FF_ADFF0;
- ff_type[1] = FF_ADFF1;
+ ff_type = FF_ADFF;
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;
+ ff_type = FF_ADFFE;
pol_c = celltype[7];
pol_r = celltype[8];
srval = celltype[9];
- pol_e = celltype[10];
+ pol_ce = celltype[10];
+ } else if (celltype.substr(0, 8) == "$_ALDFF_" && celltype.size() == 11 && celltype[10] == '_') {
+ ff_type = FF_ALDFF;
+ pol_c = celltype[8];
+ pol_l = celltype[9];
+ } else if (celltype.substr(0, 9) == "$_ALDFFE_" && celltype.size() == 13 && celltype[12] == '_') {
+ ff_type = FF_ALDFFE;
+ pol_c = celltype[9];
+ pol_l = celltype[10];
+ pol_ce = celltype[11];
} else if (celltype.substr(0, 8) == "$_DFFSR_" && celltype.size() == 12 && celltype[11] == '_') {
- ff_type[0] = FF_DFFSR;
+ ff_type = 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;
+ ff_type = FF_DFFSRE;
pol_c = celltype[9];
pol_s = celltype[10];
pol_r = celltype[11];
- pol_e = celltype[12];
+ pol_ce = celltype[12];
} else if (celltype.substr(0, 7) == "$_SDFF_" && celltype.size() == 11 && celltype[10] == '_') {
- ff_type[0] = FF_SDFF0;
- ff_type[1] = FF_SDFF1;
+ ff_type = FF_SDFF;
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;
+ ff_type = FF_SDFFE;
pol_c = celltype[8];
pol_r = celltype[9];
srval = celltype[10];
- pol_e = celltype[11];
+ pol_ce = celltype[11];
} else if (celltype.substr(0, 9) == "$_SDFFCE_" && celltype.size() == 14 && celltype[13] == '_') {
- ff_type[0] = FF_SDFFCE0;
- ff_type[1] = FF_SDFFCE1;
+ ff_type = FF_SDFFCE;
pol_c = celltype[9];
pol_r = celltype[10];
srval = celltype[11];
- pol_e = celltype[12];
+ pol_ce = celltype[12];
} else if (celltype.substr(0, 9) == "$_DLATCH_" && celltype.size() == 11 && celltype[10] == '_') {
- ff_type[0] = FF_DLATCH;
- pol_e = celltype[9];
+ ff_type = FF_DLATCH;
+ pol_l = 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];
+ ff_type = FF_ADLATCH;
+ pol_l = 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];
+ ff_type = FF_DLATCHSR;
+ pol_l = celltype[11];
pol_s = celltype[12];
pol_r = celltype[13];
} else {
@@ -1201,9 +1127,10 @@ unrecognized:
int match = 0;
for (auto pair : {
std::make_pair(pol_c, NEG_C),
- std::make_pair(pol_e, NEG_E),
+ std::make_pair(pol_l, NEG_L),
std::make_pair(pol_s, NEG_S),
std::make_pair(pol_r, NEG_R),
+ std::make_pair(pol_ce, NEG_CE),
}) {
if (pair.first == 'N') {
mask |= pair.second;
@@ -1214,40 +1141,33 @@ unrecognized:
goto unrecognized;
}
}
+ int initmask;
+ if (inittype == "x") {
+ initmask = 0x111;
+ } else if (inittype == "0") {
+ initmask = 0x333;
+ } else if (inittype == "1") {
+ initmask = 0x555;
+ } else if (inittype == "r") {
+ if (srval == 0)
+ log_error("init type r not valid for cell type %s.\n", celltype.c_str());
+ initmask = 0x537;
+ } else if (inittype == "01") {
+ initmask = 0x777;
+ } else {
+ log_error("unrecognized init type %s for cell type %s.\n", inittype.c_str(), celltype.c_str());
+ }
if (srval == '0') {
- ff_type[1] = NUM_FFTYPES;
+ initmask &= 0x0ff;
} else if (srval == '1') {
- ff_type[0] = NUM_FFTYPES;
+ initmask &= 0xf0f;
} 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;
- }
+ for (int neg = 0; neg < NUM_NEG; neg++)
+ if ((neg & mask) == match)
+ supported_cells_neg[ff_type][neg] |= initmask;
+ supported_cells[ff_type] |= initmask;
continue;
} else if (args[argidx] == "-mince" && argidx + 1 < args.size()) {
mince = atoi(args[++argidx].c_str());
@@ -1260,13 +1180,21 @@ unrecognized:
}
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];
+ supported_aldff = supported_cells[FF_ALDFF] | supported_cells[FF_ALDFFE] | supported_dffsr;
+ supported_aldffe = supported_cells[FF_ALDFFE] | supported_cells[FF_DFFSRE];
+ supported_adff = supported_cells[FF_ADFF] | supported_cells[FF_ADFFE] | supported_dffsr | supported_aldff;
+ supported_adffe = supported_cells[FF_ADFFE] | supported_cells[FF_ALDFFE] | supported_cells[FF_DFFSRE];
+ supported_sdff = supported_cells[FF_SDFF] | supported_cells[FF_SDFFE] | supported_cells[FF_SDFFCE];
+ supported_dff = supported_cells[FF_DFF] | supported_cells[FF_DFFE] | supported_adff | supported_sdff;
+ supported_dffe = supported_cells[FF_DFFE] | supported_cells[FF_DFFSRE] | supported_cells[FF_ALDFFE] | supported_cells[FF_ADFFE] | supported_cells[FF_SDFFE] | supported_cells[FF_SDFFCE];
+ supported_sr_plain = supported_dffsr | supported_cells[FF_DLATCHSR] | supported_cells[FF_SR];
+ supported_sr = supported_sr_plain;
+ supported_sr |= (supported_cells[FF_ADLATCH] >> 4 & 7) * 0x111;
+ supported_sr |= (flip_initmask(supported_cells[FF_ADLATCH]) >> 4 & 7) * 0x111;
+ supported_dlatch_plain = supported_cells[FF_DLATCH] | supported_cells[FF_ADLATCH] | supported_cells[FF_DLATCHSR] | supported_cells[FF_ALDFF] | supported_cells[FF_ALDFFE];
+ supported_dlatch = supported_dlatch_plain | supported_sr_plain;
+ supported_rlatch = supported_adff | (supported_dlatch & 7) * 0x111;
+ supported_adlatch = supported_cells[FF_ADLATCH] | supported_cells[FF_DLATCHSR];
for (auto module : design->selected_modules())
{
@@ -1281,36 +1209,20 @@ unrecognized:
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]]++;
- }
+ FfData ff(&initvals, cell);
+ if (ff.has_ce && ff.sig_ce[0].wire)
+ ce_used[ff.sig_ce[0]] += ff.width;
+ if (ff.has_srst && ff.sig_srst[0].wire)
+ srst_used[ff.sig_srst[0]] += ff.width;
}
}
-
- // 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);
+ FfData ff(&initvals, cell);
+ legalize_ff(ff);
}
-
- for (auto cell: ff_cells)
- handle_ff(cell);
}
sigmap.clear();
diff --git a/passes/techmap/dffunmap.cc b/passes/techmap/dffunmap.cc
index fb107ff75..7312015f1 100644
--- a/passes/techmap/dffunmap.cc
+++ b/passes/techmap/dffunmap.cc
@@ -84,21 +84,20 @@ struct DffunmapPass : public Pass {
continue;
if (ce_only) {
- if (!ff.has_en)
+ if (!ff.has_ce)
continue;
- ff.unmap_ce(mod);
+ ff.unmap_ce();
} else if (srst_only) {
if (!ff.has_srst)
continue;
- ff.unmap_srst(mod);
+ ff.unmap_srst();
} else {
- if (!ff.has_en && !ff.has_srst)
+ if (!ff.has_ce && !ff.has_srst)
continue;
- ff.unmap_ce_srst(mod);
+ ff.unmap_ce_srst();
}
- mod->remove(cell);
- ff.emit(mod, name);
+ ff.emit();
}
}
}
diff --git a/passes/techmap/extract_reduce.cc b/passes/techmap/extract_reduce.cc
index 07b4200cc..892e9a364 100644
--- a/passes/techmap/extract_reduce.cc
+++ b/passes/techmap/extract_reduce.cc
@@ -152,10 +152,10 @@ struct ExtractReducePass : public Pass
log_assert(y.size() == 1);
// Should only continue if there is one fanout back into a cell (not to a port)
- if (sig_to_sink[y[0]].size() != 1)
+ if (sig_to_sink[y].size() != 1 || port_sigs.count(y))
break;
- x = *sig_to_sink[y[0]].begin();
+ x = *sig_to_sink[y].begin();
}
sinks.insert(head_cell);
@@ -183,13 +183,15 @@ struct ExtractReducePass : public Pass
continue;
}
+ auto xy = sigmap(x->getPort(ID::Y));
+
//If this signal drives a port, add it to the sinks
//(even though it may not be the end of a chain)
- if(port_sigs.count(x) && !consumed_cells.count(x))
+ if(port_sigs.count(xy) && !consumed_cells.count(x))
sinks.insert(x);
//It's a match, search everything out from it
- auto& next = sig_to_sink[x];
+ auto& next = sig_to_sink[xy];
for(auto z : next)
next_loads.insert(z);
}
@@ -224,89 +226,60 @@ struct ExtractReducePass : public Pass
if(consumed_cells.count(head_cell))
continue;
- pool<Cell*> cur_supercell;
+ dict<SigBit, int> sources;
+ int inner_cells = 0;
std::deque<Cell*> bfs_queue = {head_cell};
while (bfs_queue.size())
{
Cell* x = bfs_queue.front();
bfs_queue.pop_front();
- cur_supercell.insert(x);
+ for (auto port: {ID::A, ID::B}) {
+ auto bit = sigmap(x->getPort(port)[0]);
- auto a = sigmap(x->getPort(ID::A));
- log_assert(a.size() == 1);
+ bool sink_single = sig_to_sink[bit].size() == 1 && !port_sigs.count(bit);
- // Must have only one sink unless we're going off chain
- // XXX: Check that it is indeed this node?
- if( allow_off_chain || (sig_to_sink[a[0]].size() + port_sigs.count(a[0]) == 1) )
- {
- Cell* cell_a = sig_to_driver[a[0]];
- if(cell_a && IsRightType(cell_a, gt))
- {
- // The cell here is the correct type, and it's definitely driving
- // this current cell.
- bfs_queue.push_back(cell_a);
- }
- }
+ Cell* drv = sig_to_driver[bit];
+ bool drv_ok = drv && drv->type == head_cell->type;
- auto b = sigmap(x->getPort(ID::B));
- log_assert(b.size() == 1);
-
- // Must have only one sink
- // XXX: Check that it is indeed this node?
- if( allow_off_chain || (sig_to_sink[b[0]].size() + port_sigs.count(b[0]) == 1) )
- {
- Cell* cell_b = sig_to_driver[b[0]];
- if(cell_b && IsRightType(cell_b, gt))
- {
- // The cell here is the correct type, and it's definitely driving only
- // this current cell.
- bfs_queue.push_back(cell_b);
+ if (drv_ok && (allow_off_chain || sink_single)) {
+ inner_cells++;
+ bfs_queue.push_back(drv);
+ } else {
+ sources[bit]++;
}
}
}
- log(" Cells:\n");
- for (auto x : cur_supercell)
- log(" %s\n", x->name.c_str());
-
- if (cur_supercell.size() > 1)
+ if (inner_cells)
{
// Worth it to create reduce cell
log(" Creating $reduce_* cell!\n");
- pool<SigBit> input_pool;
- pool<SigBit> input_pool_intermed;
- for (auto x : cur_supercell)
- {
- input_pool.insert(sigmap(x->getPort(ID::A))[0]);
- input_pool.insert(sigmap(x->getPort(ID::B))[0]);
- input_pool_intermed.insert(sigmap(x->getPort(ID::Y))[0]);
- }
- SigSpec input;
- for (auto b : input_pool)
- if (input_pool_intermed.count(b) == 0)
- input.append(b);
-
SigBit output = sigmap(head_cell->getPort(ID::Y)[0]);
- auto new_reduce_cell = module->addCell(NEW_ID,
- gt == GateType::And ? ID($reduce_and) :
- gt == GateType::Or ? ID($reduce_or) :
- gt == GateType::Xor ? ID($reduce_xor) : "");
- new_reduce_cell->setParam(ID::A_SIGNED, 0);
- new_reduce_cell->setParam(ID::A_WIDTH, input.size());
- new_reduce_cell->setParam(ID::Y_WIDTH, 1);
- new_reduce_cell->setPort(ID::A, input);
- new_reduce_cell->setPort(ID::Y, output);
-
- if(allow_off_chain)
- consumed_cells.insert(head_cell);
- else
- {
- for (auto x : cur_supercell)
- consumed_cells.insert(x);
+ SigSpec input;
+ for (auto it : sources) {
+ bool cond;
+ if (head_cell->type == ID($_XOR_))
+ cond = it.second & 1;
+ else
+ cond = it.second != 0;
+ if (cond)
+ input.append(it.first);
+ }
+
+ if (head_cell->type == ID($_AND_)) {
+ module->addReduceAnd(NEW_ID, input, output);
+ } else if (head_cell->type == ID($_OR_)) {
+ module->addReduceOr(NEW_ID, input, output);
+ } else if (head_cell->type == ID($_XOR_)) {
+ module->addReduceXor(NEW_ID, input, output);
+ } else {
+ log_assert(false);
}
+
+ consumed_cells.insert(head_cell);
}
}
}
diff --git a/passes/techmap/flatten.cc b/passes/techmap/flatten.cc
index 616fee3f5..7e6df5d2c 100644
--- a/passes/techmap/flatten.cc
+++ b/passes/techmap/flatten.cc
@@ -77,7 +77,7 @@ struct FlattenWorker
{
bool ignore_wb = false;
- void flatten_cell(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, std::vector<RTLIL::Cell*> &new_cells)
+ void flatten_cell(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, SigMap &sigmap, std::vector<RTLIL::Cell*> &new_cells)
{
// Copy the contents of the flattened cell
@@ -165,7 +165,6 @@ struct FlattenWorker
for (auto bit : tpl_conn.first)
tpl_driven.insert(bit);
- SigMap sigmap(module);
for (auto &port_it : cell->connections())
{
IdString port_name = port_it.first;
@@ -218,6 +217,7 @@ struct FlattenWorker
log_id(module), log_id(cell), log_id(port_it.first), log_signal(new_conn.first), log_signal(new_conn.second));
module->connect(new_conn);
+ sigmap.add(new_conn.first, new_conn.second);
}
module->remove(cell);
@@ -228,6 +228,7 @@ struct FlattenWorker
if (!design->selected(module) || module->get_blackbox_attribute(ignore_wb))
return;
+ SigMap sigmap(module);
std::vector<RTLIL::Cell*> worklist = module->selected_cells();
while (!worklist.empty())
{
@@ -251,7 +252,7 @@ struct FlattenWorker
// If a design is fully selected and has a top module defined, topological sorting ensures that all cells
// added during flattening are black boxes, and flattening is finished in one pass. However, when flattening
// individual modules, this isn't the case, and the newly added cells might have to be flattened further.
- flatten_cell(design, module, cell, tpl, worklist);
+ flatten_cell(design, module, cell, tpl, sigmap, worklist);
}
}
};
diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc
index 45fa5f226..437ad5156 100644
--- a/passes/techmap/iopadmap.cc
+++ b/passes/techmap/iopadmap.cc
@@ -43,26 +43,28 @@ struct IopadmapPass : public Pass {
log("can only map to very simple PAD cells. Use 'techmap' to further map\n");
log("the resulting cells to more sophisticated PAD cells.\n");
log("\n");
- log(" -inpad <celltype> <portname>[:<portname>]\n");
+ log(" -inpad <celltype> <in_port>[:<ext_port>]\n");
log(" Map module input ports to the given cell type with the\n");
log(" given output port name. if a 2nd portname is given, the\n");
- log(" signal is passed through the pad call, using the 2nd\n");
+ log(" signal is passed through the pad cell, using the 2nd\n");
log(" portname as the port facing the module port.\n");
log("\n");
- log(" -outpad <celltype> <portname>[:<portname>]\n");
- log(" -inoutpad <celltype> <portname>[:<portname>]\n");
+ log(" -outpad <celltype> <out_port>[:<ext_port>]\n");
+ log(" -inoutpad <celltype> <io_port>[:<ext_port>]\n");
log(" Similar to -inpad, but for output and inout ports.\n");
log("\n");
- log(" -toutpad <celltype> <portname>:<portname>[:<portname>]\n");
+ log(" -toutpad <celltype> <oe_port>:<out_port>[:<ext_port>]\n");
log(" Merges $_TBUF_ cells into the output pad cell. This takes precedence\n");
log(" over the other -outpad cell. The first portname is the enable input\n");
- log(" of the tristate driver.\n");
+ log(" of the tristate driver, which can be prefixed with `~` for negative\n");
+ log(" polarity enable.\n");
log("\n");
- log(" -tinoutpad <celltype> <portname>:<portname>:<portname>[:<portname>]\n");
+ log(" -tinoutpad <celltype> <oe_port>:<in_port>:<out_port>[:<ext_port>]\n");
log(" Merges $_TBUF_ cells into the inout pad cell. This takes precedence\n");
log(" over the other -inoutpad cell. The first portname is the enable input\n");
log(" of the tristate driver and the 2nd portname is the internal output\n");
- log(" buffering the external signal.\n");
+ log(" buffering the external signal. Like with `-toutpad`, the enable can\n");
+ log(" be marked as negative polarity by prefixing the name with `~`.\n");
log("\n");
log(" -ignore <celltype> <portname>[:<portname>]*\n");
log(" Skips mapping inputs/outputs that are already connected to given\n");
@@ -106,6 +108,7 @@ struct IopadmapPass : public Pass {
std::string inoutpad_celltype, inoutpad_portname_io, inoutpad_portname_pad;
std::string toutpad_celltype, toutpad_portname_oe, toutpad_portname_i, toutpad_portname_pad;
std::string tinoutpad_celltype, tinoutpad_portname_oe, tinoutpad_portname_o, tinoutpad_portname_i, tinoutpad_portname_pad;
+ bool toutpad_neg_oe = false, tinoutpad_neg_oe = false;
std::string widthparam, nameparam;
pool<pair<IdString, IdString>> ignore;
bool flag_bits = false;
@@ -137,6 +140,10 @@ struct IopadmapPass : public Pass {
toutpad_portname_oe = args[++argidx];
split_portname_pair(toutpad_portname_oe, toutpad_portname_i);
split_portname_pair(toutpad_portname_i, toutpad_portname_pad);
+ if (toutpad_portname_oe[0] == '~') {
+ toutpad_neg_oe = true;
+ toutpad_portname_oe = toutpad_portname_oe.substr(1);
+ }
continue;
}
if (arg == "-tinoutpad" && argidx+2 < args.size()) {
@@ -145,6 +152,10 @@ struct IopadmapPass : public Pass {
split_portname_pair(tinoutpad_portname_oe, tinoutpad_portname_o);
split_portname_pair(tinoutpad_portname_o, tinoutpad_portname_i);
split_portname_pair(tinoutpad_portname_i, tinoutpad_portname_pad);
+ if (tinoutpad_portname_oe[0] == '~') {
+ tinoutpad_neg_oe = true;
+ tinoutpad_portname_oe = tinoutpad_portname_oe.substr(1);
+ }
continue;
}
if (arg == "-ignore" && argidx+2 < args.size()) {
@@ -318,6 +329,8 @@ struct IopadmapPass : public Pass {
module->uniquify(stringf("$iopadmap$%s.%s[%d]", log_id(module), log_id(wire), i)),
RTLIL::escape_id(tinoutpad_celltype));
+ if (tinoutpad_neg_oe)
+ en_sig = module->NotGate(NEW_ID, en_sig);
cell->setPort(RTLIL::escape_id(tinoutpad_portname_oe), en_sig);
cell->attributes[ID::keep] = RTLIL::Const(1);
@@ -340,6 +353,8 @@ struct IopadmapPass : public Pass {
module->uniquify(stringf("$iopadmap$%s.%s[%d]", log_id(module), log_id(wire), i)),
RTLIL::escape_id(toutpad_celltype));
+ if (toutpad_neg_oe)
+ en_sig = module->NotGate(NEW_ID, en_sig);
cell->setPort(RTLIL::escape_id(toutpad_portname_oe), en_sig);
cell->setPort(RTLIL::escape_id(toutpad_portname_i), data_sig);
cell->attributes[ID::keep] = RTLIL::Const(1);
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index b65224c71..7d8dba439 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -19,6 +19,7 @@
#include "simplemap.h"
#include "kernel/sigtools.h"
+#include "kernel/ff.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -298,6 +299,30 @@ void simplemap_tribuf(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
+void simplemap_bmux(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+ SigSpec sel = cell->getPort(ID::S);
+ SigSpec data = cell->getPort(ID::A);
+ int width = GetSize(cell->getPort(ID::Y));
+
+ for (int idx = 0; idx < GetSize(sel); idx++) {
+ SigSpec new_data = module->addWire(NEW_ID, GetSize(data)/2);
+ for (int i = 0; i < GetSize(new_data); i += width) {
+ for (int k = 0; k < width; k++) {
+ RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_));
+ gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+ gate->setPort(ID::A, data[i*2+k]);
+ gate->setPort(ID::B, data[i*2+width+k]);
+ gate->setPort(ID::S, sel[idx]);
+ gate->setPort(ID::Y, new_data[i+k]);
+ }
+ }
+ data = new_data;
+ }
+
+ module->connect(cell->getPort(ID::Y), data);
+}
+
void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell)
{
SigSpec lut_ctrl = cell->getPort(ID::A);
@@ -305,7 +330,6 @@ void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell)
lut_data.extend_u0(1 << cell->getParam(ID::WIDTH).as_int());
for (int idx = 0; GetSize(lut_data) > 1; idx++) {
- SigSpec sig_s = lut_ctrl[idx];
SigSpec new_lut_data = module->addWire(NEW_ID, GetSize(lut_data)/2);
for (int i = 0; i < GetSize(lut_data); i += 2) {
RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_));
@@ -367,276 +391,13 @@ void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell)
module->connect(RTLIL::SigSig(sig_y, sig_ab));
}
-void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell)
-{
- int width = cell->parameters.at(ID::WIDTH).as_int();
- 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_s = cell->getPort(ID::SET);
- RTLIL::SigSpec sig_r = cell->getPort(ID::CLR);
- RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
-
- std::string gate_type = stringf("$_SR_%c%c_", 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::S, sig_s[i]);
- gate->setPort(ID::R, sig_r[i]);
- gate->setPort(ID::Q, sig_q[i]);
- }
-}
-
-void simplemap_ff(RTLIL::Module *module, RTLIL::Cell *cell)
-{
- int width = cell->parameters.at(ID::WIDTH).as_int();
-
- RTLIL::SigSpec sig_d = cell->getPort(ID::D);
- RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
-
- IdString gate_type = ID($_FF_);
-
- 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::D, sig_d[i]);
- gate->setPort(ID::Q, sig_q[i]);
- }
-}
-
-void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_ff(RTLIL::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';
-
- RTLIL::SigSpec sig_clk = cell->getPort(ID::CLK);
- RTLIL::SigSpec sig_d = cell->getPort(ID::D);
- RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
-
- IdString gate_type = stringf("$_DFF_%c_", clk_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::D, sig_d[i]);
- gate->setPort(ID::Q, sig_q[i]);
- }
-}
-
-void simplemap_dffe(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 en_pol = cell->parameters.at(ID::EN_POLARITY).as_bool() ? 'P' : 'N';
-
- RTLIL::SigSpec sig_clk = cell->getPort(ID::CLK);
- RTLIL::SigSpec sig_en = cell->getPort(ID::EN);
- RTLIL::SigSpec sig_d = cell->getPort(ID::D);
- RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
-
- IdString gate_type = stringf("$_DFFE_%c%c_", clk_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::E, sig_en);
- gate->setPort(ID::D, sig_d[i]);
- gate->setPort(ID::Q, sig_q[i]);
- }
-}
-
-void simplemap_dffsr(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 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_clk = cell->getPort(ID::CLK);
- 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("$_DFFSR_%c%c%c_", clk_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::C, sig_clk);
- 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_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 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';
-
- 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(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("$_%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]);
- }
-}
-
-void simplemap_dlatch(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';
-
- RTLIL::SigSpec sig_en = cell->getPort(ID::EN);
- RTLIL::SigSpec sig_d = cell->getPort(ID::D);
- RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
-
- IdString gate_type = stringf("$_DLATCH_%c_", 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::E, sig_en);
- gate->setPort(ID::D, sig_d[i]);
- gate->setPort(ID::Q, sig_q[i]);
- }
-}
-
-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]);
+ FfData ff(nullptr, cell);
+ for (int i = 0; i < ff.width; i++) {
+ FfData fff = ff.slice({i});
+ fff.is_fine = true;
+ fff.emit();
}
}
@@ -662,24 +423,27 @@ void simplemap_get_mappers(dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)>
mappers[ID($nex)] = simplemap_eqne;
mappers[ID($mux)] = simplemap_mux;
mappers[ID($tribuf)] = simplemap_tribuf;
+ mappers[ID($bmux)] = simplemap_bmux;
mappers[ID($lut)] = simplemap_lut;
mappers[ID($sop)] = simplemap_sop;
mappers[ID($slice)] = simplemap_slice;
mappers[ID($concat)] = simplemap_concat;
- mappers[ID($sr)] = simplemap_sr;
+ mappers[ID($sr)] = simplemap_ff;
mappers[ID($ff)] = simplemap_ff;
- mappers[ID($dff)] = simplemap_dff;
- mappers[ID($dffe)] = simplemap_dffe;
- mappers[ID($dffsr)] = simplemap_dffsr;
- 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;
+ mappers[ID($dff)] = simplemap_ff;
+ mappers[ID($dffe)] = simplemap_ff;
+ mappers[ID($dffsr)] = simplemap_ff;
+ mappers[ID($dffsre)] = simplemap_ff;
+ mappers[ID($adff)] = simplemap_ff;
+ mappers[ID($sdff)] = simplemap_ff;
+ mappers[ID($adffe)] = simplemap_ff;
+ mappers[ID($sdffe)] = simplemap_ff;
+ mappers[ID($sdffce)] = simplemap_ff;
+ mappers[ID($aldff)] = simplemap_ff;
+ mappers[ID($aldffe)] = simplemap_ff;
+ mappers[ID($dlatch)] = simplemap_ff;
+ mappers[ID($adlatch)] = simplemap_ff;
+ mappers[ID($dlatchsr)] = simplemap_ff;
}
void simplemap(RTLIL::Module *module, RTLIL::Cell *cell)
@@ -712,7 +476,7 @@ 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, $dffe, $dffsr, $dffsre, $adff, $adffe, $sdff, $sdffe, $sdffce, $dlatch, $adlatch, $dlatchsr\n");
+ log(" $sr, $ff, $dff, $dffe, $dffsr, $dffsre, $adff, $adffe, $aldff, $aldffe, $sdff, $sdffe, $sdffce, $dlatch, $adlatch, $dlatchsr\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
diff --git a/passes/techmap/simplemap.h b/passes/techmap/simplemap.h
index 03a8fb36f..c7654f68c 100644
--- a/passes/techmap/simplemap.h
+++ b/passes/techmap/simplemap.h
@@ -34,12 +34,7 @@ extern void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell);
extern void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell);
extern void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell);
extern void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell);
-extern void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell);
-extern void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell);
-extern void simplemap_dffe(RTLIL::Module *module, RTLIL::Cell *cell);
-extern void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell);
-extern void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell);
-extern void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_ff(RTLIL::Module *module, RTLIL::Cell *cell);
extern void simplemap(RTLIL::Module *module, RTLIL::Cell *cell);
extern void simplemap_get_mappers(dict<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index a69a6d460..5cd78fe28 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -377,10 +377,12 @@ struct TechmapWorker
if (c->attributes.count(ID::src))
c->add_strpool_attribute(ID::src, extra_src_attrs);
- if (techmap_replace_cell)
+ if (techmap_replace_cell) {
for (auto attr : cell->attributes)
if (!c->attributes.count(attr.first))
c->attributes[attr.first] = attr.second;
+ c->attributes.erase(ID::reprocess_after);
+ }
}
for (auto &it : tpl->connections()) {
diff --git a/passes/techmap/tribuf.cc b/passes/techmap/tribuf.cc
index f92b4cdb0..b45cd268a 100644
--- a/passes/techmap/tribuf.cc
+++ b/passes/techmap/tribuf.cc
@@ -26,10 +26,12 @@ PRIVATE_NAMESPACE_BEGIN
struct TribufConfig {
bool merge_mode;
bool logic_mode;
+ bool formal_mode;
TribufConfig() {
merge_mode = false;
logic_mode = false;
+ formal_mode = false;
}
};
@@ -55,7 +57,7 @@ struct TribufWorker {
dict<SigSpec, vector<Cell*>> tribuf_cells;
pool<SigBit> output_bits;
- if (config.logic_mode)
+ if (config.logic_mode || config.formal_mode)
for (auto wire : module->wires())
if (wire->port_output)
for (auto bit : sigmap(wire))
@@ -102,22 +104,54 @@ struct TribufWorker {
}
}
- if (config.merge_mode || config.logic_mode)
+ if (config.merge_mode || config.logic_mode || config.formal_mode)
{
for (auto &it : tribuf_cells)
{
bool no_tribuf = false;
- if (config.logic_mode) {
+ if (config.logic_mode && !config.formal_mode) {
no_tribuf = true;
for (auto bit : it.first)
if (output_bits.count(bit))
no_tribuf = false;
}
+ if (config.formal_mode)
+ no_tribuf = true;
+
if (GetSize(it.second) <= 1 && !no_tribuf)
continue;
+ if (config.formal_mode && GetSize(it.second) >= 2) {
+ for (auto cell : it.second) {
+ SigSpec others_s;
+
+ for (auto other_cell : it.second) {
+ if (other_cell == cell)
+ continue;
+ else if (other_cell->type == ID($tribuf))
+ others_s.append(other_cell->getPort(ID::EN));
+ else
+ others_s.append(other_cell->getPort(ID::E));
+ }
+
+ auto cell_s = cell->type == ID($tribuf) ? cell->getPort(ID::EN) : cell->getPort(ID::E);
+
+ auto other_s = module->ReduceOr(NEW_ID, others_s);
+
+ auto conflict = module->And(NEW_ID, cell_s, other_s);
+
+ std::string name = stringf("$tribuf_conflict$%s", log_id(cell->name));
+ auto assert_cell = module->addAssert(name, module->Not(NEW_ID, conflict), SigSpec(true));
+
+ assert_cell->set_src_attribute(cell->get_src_attribute());
+ assert_cell->set_bool_attribute(ID::keep);
+
+ module->design->scratchpad_set_bool("tribuf.added_something", true);
+ }
+ }
+
SigSpec pmux_b, pmux_s;
for (auto cell : it.second) {
if (cell->type == ID($tribuf))
@@ -159,6 +193,11 @@ struct TribufPass : public Pass {
log(" convert tri-state buffers that do not drive output ports\n");
log(" to non-tristate logic. this option implies -merge.\n");
log("\n");
+ log(" -formal\n");
+ log(" convert all tri-state buffers to non-tristate logic and\n");
+ log(" add a formal assertion that no two buffers are driving the\n");
+ log(" same net simultaneously. this option implies -merge.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
@@ -176,6 +215,10 @@ struct TribufPass : public Pass {
config.logic_mode = true;
continue;
}
+ if (args[argidx] == "-formal") {
+ config.formal_mode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
diff --git a/passes/techmap/zinit.cc b/passes/techmap/zinit.cc
index 7c5b73c90..cc208c516 100644
--- a/passes/techmap/zinit.cc
+++ b/passes/techmap/zinit.cc
@@ -20,6 +20,7 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/ffinit.h"
+#include "kernel/ff.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -60,123 +61,25 @@ struct ZinitPass : public Pass {
SigMap sigmap(module);
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($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_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($_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())
{
- if (!dff_types.count(cell->type))
- continue;
-
- SigSpec sig_d = sigmap(cell->getPort(ID::D));
- SigSpec sig_q = sigmap(cell->getPort(ID::Q));
-
- if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1)
+ if (!RTLIL::builtin_ff_cell_types().count(cell->type))
continue;
- Const initval = initvals(sig_q);
- Const newval = initval;
- initvals.remove_init(sig_q);
-
- 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]);
- 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);
+ FfData ff(&initvals, cell);
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.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_),
- ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_)))
- {
- t[8] = (t[8] == '0' ? '1' : '0');
- }
- 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($_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');
- }
- cell->type = t;
+ log_signal(ff.sig_q), log_signal(ff.val_init));
+
+ pool<int> bits;
+ for (int i = 0; i < ff.width; i++) {
+ if (ff.val_init.bits[i] == State::S1)
+ bits.insert(i);
+ else if (ff.val_init.bits[i] != State::S0 && all_mode)
+ ff.val_init.bits[i] = State::S0;
}
+ ff.flip_bits(bits);
+ ff.emit();
}
}
}