diff options
Diffstat (limited to 'passes/techmap')
-rw-r--r-- | passes/techmap/Makefile.inc | 2 | ||||
-rw-r--r-- | passes/techmap/abc.cc | 412 | ||||
-rw-r--r-- | passes/techmap/abc9.cc | 8 | ||||
-rw-r--r-- | passes/techmap/abc9_ops.cc | 82 | ||||
-rw-r--r-- | passes/techmap/bmuxmap.cc | 76 | ||||
-rw-r--r-- | passes/techmap/demuxmap.cc | 80 | ||||
-rw-r--r-- | passes/techmap/dfflegalize.cc | 1866 | ||||
-rw-r--r-- | passes/techmap/dffunmap.cc | 13 | ||||
-rw-r--r-- | passes/techmap/extract_reduce.cc | 107 | ||||
-rw-r--r-- | passes/techmap/flatten.cc | 7 | ||||
-rw-r--r-- | passes/techmap/iopadmap.cc | 31 | ||||
-rw-r--r-- | passes/techmap/simplemap.cc | 332 | ||||
-rw-r--r-- | passes/techmap/simplemap.h | 7 | ||||
-rw-r--r-- | passes/techmap/techmap.cc | 4 | ||||
-rw-r--r-- | passes/techmap/tribuf.cc | 49 | ||||
-rw-r--r-- | passes/techmap/zinit.cc | 123 |
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(); } } } |