abc9_ops: add 'dff' label for auto handling of (* abc9_flop *) boxes
authorEddie Hung <eddie@fpgeh.com>
Mon, 13 Apr 2020 16:38:07 +0000 (09:38 -0700)
committerEddie Hung <eddie@fpgeh.com>
Thu, 14 May 2020 17:33:56 +0000 (10:33 -0700)
backends/aiger/xaiger.cc
passes/hierarchy/submod.cc
passes/techmap/abc9.cc
passes/techmap/abc9_ops.cc
techlibs/common/abc9_model.v
techlibs/xilinx/abc9_map.v
techlibs/xilinx/abc9_unmap.v
techlibs/xilinx/cells_sim.v
techlibs/xilinx/synth_xilinx.cc

index d014c4ec6c74dc1b5f36d31c69e73030fb7d5d6c..2e2ca70188bf0e356c36c82e0f11a7329b0200d8 100644 (file)
@@ -616,7 +616,6 @@ struct XAigerWriter
 
                        dict<SigBit, int> clk_to_mergeability;
 
-                       bool nonzero_warned = false;
                        for (const auto &i : ff_bits) {
                                const SigBit &d = i.first;
                                const Cell *cell = i.second;
@@ -633,15 +632,10 @@ struct XAigerWriter
                                        write_r_buffer(mergeability);
                                else log_abort();
 
-                               Const init = cell->attributes.at(ID::abc9_init, State::Sx);
+                               Const init = cell->attributes.at(ID::abc9_init);
                                log_assert(GetSize(init) == 1);
-                               if (init == State::S1) {
-                                       if (!nonzero_warned) {
-                                               log_warning("Module '%s' contains $_DFF_[NP]_ cell with non-zero initial state -- unsupported by ABC9.\n", log_id(module));
-                                               nonzero_warned = true;
-                                       }
+                               if (init == State::S1)
                                        write_s_buffer(1);
-                               }
                                else if (init == State::S0)
                                        write_s_buffer(0);
                                else {
index 2db7cf26b83d93f8d583ec00fcd4e708f2a66dcd..1f30a5160590c9b75f44022d444cd530fa99f679 100644 (file)
@@ -389,7 +389,7 @@ struct SubmodPass : public Pass {
                        while (did_something) {
                                did_something = false;
                                std::vector<RTLIL::IdString> queued_modules;
-                               for (auto mod : design->modules())
+                               for (auto mod : design->selected_modules())
                                        if (handled_modules.count(mod->name) == 0 && design->selected_whole_module(mod->name))
                                                queued_modules.push_back(mod->name);
                                for (auto &modname : queued_modules)
index d8f2f0357063063b4634cc917775417eb2cbd472..7f3e6abcccffaeb421ca59dba4983b4574e6f506 100644 (file)
@@ -151,8 +151,8 @@ struct Abc9Pass : public ScriptPass
                log("        specified).\n");
                log("\n");
                log("    -dff\n");
-               log("        also pass $_ABC9_FF_ cells through to ABC. modules with many clock\n");
-               log("        domains are marked as such and automatically partitioned by ABC.\n");
+               log("        also pass $_DFF_[NP]_ cells through to ABC. modules with many clock\n");
+               log("        domains are supported and automatically partitioned by ABC.\n");
                log("\n");
                log("    -nocleanup\n");
                log("        when this option is used, the temporary files created by this pass\n");
@@ -274,26 +274,74 @@ struct Abc9Pass : public ScriptPass
 
        void script() YS_OVERRIDE
        {
-               if (check_label("pre")) {
+               if (check_label("check")) {
                        run("abc9_ops -check");
+               }
+
+               if (check_label("dff", "(only if -dff)")) {
+                       if (dff_mode || help_mode) {
+                               run("abc9_ops -prep_dff_hier"); // derive all used (* abc9_flop *) modules
+                               run("design -stash $abc9");
+                               run("design -copy-from $abc9 @$abc9_flops"); // copy derived modules in
+                               run("proc");
+                               run("wbflip");
+                               run("techmap");
+                               run("opt");
+                               run("abc9_ops -prep_dff_map"); // rewrite specify
+                                                                       // TODO: Select fan-in cone $_DFF_[NP]_.Q
+                               run("setattr -set submod \"$abc9_flop\" t:* t:$_DFF_N_ %d t:$_DFF_P_ %d");
+                               run("submod");
+                               run("design -copy-to $abc9 *_$abc9_flop"); // copy submod out
+                               run("delete *_$abc9_flop");
+                               if (help_mode) {
+                                       run("foreach module in design");
+                                       run("    cd <module-name>");
+                                       run("    rename <module-name>_$abc9_flop _TECHMAP_REPLACE_");
+                                       run("    cd");
+                               }
+                               else {
+                                       // Rename all submod-s to _TECHMAP_REPLACE_ to inherit name + attrs
+                                       for (auto module : active_design->selected_modules()) {
+                                               run(stringf("cd %s", log_id(module->name)));
+                                               run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str()));
+                                               run("cd");
+                                       }
+                               }
+                               run("design -stash $abc9_map");
+                               run("design -load $abc9");
+                               run("abc9_ops -prep_dff_unmap"); // create $abc9_unmap design
+                               run("techmap -map %$abc9_map"); // techmap user design into submod + $_DFF_[NP]_
+                               run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop");
+                               if (!help_mode) {
+                                       // TODO: Need a way to delete saved designs?
+                                       auto it = saved_designs.find("$abc9_map");
+                                       delete it->second;
+                                       saved_designs.erase(it);
+                                       // TODO: Need a way to delete selections
+                                       active_design->selection_vars.erase(ID($abc9_flops));
+                                       active_design->selection_vars.erase(ID($abc9_cells));
+                               }
+                       }
+               }
+
+               if (check_label("pre")) {
                        run("scc -set_attr abc9_scc_id {}");
                        if (help_mode)
                                run("abc9_ops -mark_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)");
                        else
-                               run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)");
+                               run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : ""));
                        if (help_mode)
                                run("abc9_ops -prep_lut <maxlut>", "(skip if -lut or -luts)");
                        else if (!lut_mode)
                                run(stringf("abc9_ops -prep_lut %d", maxlut));
                        if (help_mode)
-                               run("abc9_ops -prep_box [-dff]", "(skip if -box)");
-                       else if (box_file.empty())
-                               run(stringf("abc9_ops -prep_box %s", dff_mode ? "-dff" : ""));
+                               run("abc9_ops -prep_box", "(skip if -box)");
+                       else if (box_file.empty()) {
+                               run("abc9_ops -prep_box");
+                       }
                        run("select -set abc9_holes A:abc9_holes");
                        run("flatten -wb @abc9_holes");
                        run("techmap @abc9_holes");
-                       if (dff_mode || help_mode)
-                               run("abc9_ops -prep_dff", "(only if -dff)");
                        run("opt -purge @abc9_holes");
                        run("aigmap");
                        run("wbflip @abc9_holes");
@@ -304,10 +352,10 @@ struct Abc9Pass : public ScriptPass
                                run("foreach module in selection");
                                run("    abc9_ops -write_lut <abc-temp-dir>/input.lut", "(skip if '-lut' or '-luts')");
                                run("    abc9_ops -write_box <abc-temp-dir>/input.box", "(skip if '-box')");
-                               run("    write_xaiger -map <abc-temp-dir>/input.sym <abc-temp-dir>/input.xaig");
-                               run("    abc9_exe [options] -cwd <abc-temp-dir> [-lut <abc-temp-dir>/input.lut] -box <abc-temp-dir>/input.box");
+                               run("    write_xaiger -map <abc-temp-dir>/input.sym [-dff] <abc-temp-dir>/input.xaig");
+                               run("    abc9_exe [options] -cwd <abc-temp-dir> -lut [<abc-temp-dir>/input.lut] -box [<abc-temp-dir>/input.box]");
                                run("    read_aiger -xaiger -wideports -module_name <module-name>$abc9 -map <abc-temp-dir>/input.sym <abc-temp-dir>/output.aig");
-                               run("    abc9_ops -reintegrate");
+                               run("    abc9_ops -reintegrate [-dff]");
                        }
                        else {
                                auto selected_modules = active_design->selected_modules();
@@ -335,7 +383,7 @@ struct Abc9Pass : public ScriptPass
                                                run_nocheck(stringf("abc9_ops -write_lut %s/input.lut", tempdir_name.c_str()));
                                        if (box_file.empty())
                                                run_nocheck(stringf("abc9_ops -write_box %s/input.box", tempdir_name.c_str()));
-                                       run_nocheck(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()));
+                                       run_nocheck(stringf("write_xaiger -map %s/input.sym %s %s/input.xaig", tempdir_name.c_str(), dff_mode ? "-dff" : "", tempdir_name.c_str()));
 
                                        int num_outputs = active_design->scratchpad_get_int("write_xaiger.num_outputs");
 
@@ -356,7 +404,7 @@ struct Abc9Pass : public ScriptPass
                                                        abc9_exe_cmd += stringf(" -box %s", box_file.c_str());
                                                run_nocheck(abc9_exe_cmd);
                                                run_nocheck(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod), tempdir_name.c_str(), tempdir_name.c_str()));
-                                               run_nocheck("abc9_ops -reintegrate");
+                                               run_nocheck(stringf("abc9_ops -reintegrate %s", dff_mode ? "-dff" : ""));
                                        }
                                        else
                                                log("Don't call ABC as there is nothing to map.\n");
@@ -373,6 +421,19 @@ struct Abc9Pass : public ScriptPass
                                active_design->selection_stack.pop_back();
                        }
                }
+
+               if (check_label("post")) {
+                       if (dff_mode || help_mode) {
+                               run("techmap -wb -map %$abc9_unmap", "(only if -dff)"); // techmap user design from submod back to original cell
+                                                                                       //   ($_DFF_[NP]_ already shorted by -reintegrate)
+                               if (!help_mode) {
+                                       // TODO: Need a way to delete saved designs?
+                                       auto it = saved_designs.find("$abc9_unmap");
+                                       delete it->second;
+                                       saved_designs.erase(it);
+                               }
+                       }
+               }
        }
 } Abc9Pass;
 
index 1345188a45992940fc3cf54ac0afc8f3331b82aa..fe2e5c3ace7e8d48680f53f4c60e5ca90ae07f25 100644 (file)
@@ -119,81 +119,127 @@ void mark_scc(RTLIL::Module *module)
        }
 }
 
-void prep_dff(RTLIL::Module *module)
-{
-       auto design = module->design;
-       log_assert(design);
 
-       SigMap assign_map(module);
-
-       typedef SigSpec clkdomain_t;
-       dict<clkdomain_t, int> clk_to_mergeability;
+void prep_dff_hier(RTLIL::Design *design)
+{
+       pool<IdString> seen;
+       dict<RTLIL::IdString, RTLIL::Selection> selection_vars;
+       auto r YS_ATTRIBUTE(unused) = design->selection_vars.insert(std::make_pair(ID($abc9_flops), RTLIL::Selection(false)));
+       log_assert(r.second);
+       auto r2 YS_ATTRIBUTE(unused) = design->selection_vars.insert(std::make_pair(ID($abc9_cells), RTLIL::Selection(false)));
+       log_assert(r2.second);
+       auto &modules_sel = design->selection_vars.at(ID($abc9_flops));
+       auto &cells_sel = design->selection_vars.at(ID($abc9_cells));
+
+       for (auto module : design->selected_modules())
+               for (auto cell : module->cells()) {
+                       auto inst_module = design->module(cell->type);
+                       if (inst_module && inst_module->get_bool_attribute(ID::abc9_flop)) {
+                               modules_sel.select(inst_module);
+                               // Derive modules for all instantiations of (* abc9_flop *)
+                               auto derived_type = inst_module->derive(design, cell->parameters);
+                               // And remember one representative cell (for its parameters)
+                               if (modules_sel.selected_modules.insert(derived_type).second)
+                                       cells_sel.select(module, cell);
+                       }
+               }
+}
 
-       for (auto cell : module->cells()) {
-               if (cell->type != ID($__ABC9_FF_))
-                       continue;
+void prep_dff_map(RTLIL::Design *design)
+{
+       for (auto module : design->modules()) {
+               vector<Cell*> specify_cells;
+               SigBit D, Q;
+               for (auto cell : module->cells())
+                       if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) {
+                               if (D != SigBit())
+                                       log_error("More than one $_DFF_[NP]_ cell found in module '%s' marked (* abc9_flop *)\n", log_id(module));
+                               D = cell->getPort(ID::D);
+                               Q = cell->getPort(ID::Q);
+
+                               // TODO: Can we avoid doing this?
+                               // Convert (* init *) on $_DFF_[NP]_.Q to (* abc9_init *) attr on cell
+                               log_assert(GetSize(Q.wire) == 1);
+                               auto it = Q.wire->attributes.find(ID::init);
+                               Const init;
+                               if (it != Q.wire->attributes.end()) {
+                                       log_assert(GetSize(it->second) == 1);
+                                       init = it->second;
+                                       Q.wire->attributes.erase(it);
+                               }
+                               else
+                                       init = State::Sx;
+                               auto r YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID::abc9_init, init));
+                               log_assert(r.second);
+                               if (init == State::S1) {
+                                       log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(module), log_id(cell->type));
 
-               Wire *abc9_clock_wire = module->wire(stringf("%s.clock", cell->name.c_str()));
-               if (abc9_clock_wire == NULL)
-                       log_error("'%s.clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
-               SigSpec abc9_clock = assign_map(abc9_clock_wire);
+                                       module->makeblackbox();
 
-               clkdomain_t key(abc9_clock);
+                                       auto wire = module->addWire(ID(_TECHMAP_FAIL_));
+                                       wire->set_bool_attribute(ID::keep);
+                                       module->connect(wire, State::S1);
 
-               auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1));
-               auto r2  = cell->attributes.insert(ID::abc9_mergeability);
-               log_assert(r2.second);
-               r2.first->second = r.first->second;
+                                       goto continue_outer_loop;
+                               }
+                       }
+                       else if (cell->type.in(ID($specify2), ID($specify3), ID($specrule)))
+                               specify_cells.emplace_back(cell);
+               if (D == SigBit())
+                       log_error("$_DFF_[NP]_ cell not found in module '%s' marked (* abc9_flop *)\n", log_id(module));
+
+               // Rewrite $specify cells that end with $_DFF_[NP]_.Q
+               //   to $_DFF_[NP]_.D since it will be moved into
+               //   the submodule
+               for (auto cell : specify_cells) {
+                       auto DST = cell->getPort(ID::DST);
+                       DST.replace(Q, D);
+                       cell->setPort(ID::DST, DST);
+               }
+continue_outer_loop: ;
        }
+}
 
-       RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str()));
-       if (holes_module) {
-               SigMap sigmap(holes_module);
-
-               dict<SigSpec, SigSpec> replace;
-               for (auto cell : holes_module->cells().to_vector()) {
-                       if (!cell->type.in(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_)))
-                               continue;
-                       SigBit D = cell->getPort(ID::D);
-                       SigBit Q = cell->getPort(ID::Q);
-                       // Emulate async control embedded inside $_DFF_* cell with mux in front of D
-                       if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_PN0_)))
-                               D = holes_module->MuxGate(NEW_ID, State::S0, D, cell->getPort(ID::R));
-                       else if (cell->type.in(ID($_DFF_NN1_), ID($_DFF_PN1_)))
-                               D = holes_module->MuxGate(NEW_ID, State::S1, D, cell->getPort(ID::R));
-                       else if (cell->type.in(ID($_DFF_NP0_), ID($_DFF_PP0_)))
-                               D = holes_module->MuxGate(NEW_ID, D, State::S0, cell->getPort(ID::R));
-                       else if (cell->type.in(ID($_DFF_NP1_), ID($_DFF_PP1_)))
-                               D = holes_module->MuxGate(NEW_ID, D, State::S1, cell->getPort(ID::R));
-                       // Remove the $_DFF_* cell from what needs to be a combinatorial box
-                       holes_module->remove(cell);
-                       Wire *port;
-                       if (GetSize(Q.wire) == 1)
-                               port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str()));
-                       else
-                               port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset));
-                       log_assert(port);
-                       // Prepare to replace "assign <port> = $_DFF_*.Q;" with "assign <port> = $_DFF_*.D;"
-                       //   in order to extract just the combinatorial control logic that feeds the box
-                       //   (i.e. clock enable, synchronous reset, etc.)
-                       replace.insert(std::make_pair(Q,D));
-                       // Since `flatten` above would have created wires named "<cell>.Q",
-                       //   extract the pre-techmap cell name
-                       auto pos = Q.wire->name.str().rfind(".");
-                       log_assert(pos != std::string::npos);
-                       IdString driver = Q.wire->name.substr(0, pos);
-                       // And drive the signal that was previously driven by "DFF.Q" (typically
-                       //   used to implement clock-enable functionality) with the "<cell>.$abc9_currQ"
-                       //   wire (which itself is driven an by input port) we inserted above
-                       Wire *currQ = holes_module->wire(stringf("%s.abc9_ff.Q", driver.c_str()));
-                       log_assert(currQ);
-                       holes_module->connect(Q, currQ);
+void prep_dff_unmap(RTLIL::Design *design)
+{
+       dict<IdString,Cell*> derived_to_cell;
+       const auto &cells_sel = design->selection_vars.at(ID($abc9_cells));
+       for (auto &i : cells_sel.selected_members) {
+               auto module = design->module(i.first);
+               for (auto cell_name : i.second) {
+                       auto cell = module->cell(cell_name);
+                       log_assert(cell);
+                       auto inst_module = design->module(cell->type);
+                       log_assert(inst_module);
+                       auto derived_type = inst_module->derive(design, cell->parameters);
+                       derived_to_cell.insert(std::make_pair(derived_type, cell));
                }
+       }
 
-               for (auto &conn : holes_module->connections_)
-                       conn.second = replace.at(sigmap(conn.second), conn.second);
+       Design *unmap_design = new Design;
+
+       // Create the reverse techmap rule -- (* abc9_box *) back to flop
+       for (const auto &i : derived_to_cell) {
+               auto module_name = i.first;
+               auto flop_module = design->module(module_name.str() + "_$abc9_flop");
+               if (!flop_module)
+                       continue; // May not exist if init = 1'b1
+
+               auto unmap_module = unmap_design->addModule(flop_module->name);
+               for (auto port : flop_module->ports)
+                       unmap_module->addWire(port, flop_module->wire(port));
+               unmap_module->ports = flop_module->ports;
+               unmap_module->check();
+
+               auto orig_cell = i.second;
+               auto unmap_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, orig_cell->type);
+               for (const auto &conn : orig_cell->connections())
+                       unmap_cell->setPort(conn.first, unmap_module->wire(conn.first));
+               unmap_cell->parameters = orig_cell->parameters;
        }
+
+       auto r YS_ATTRIBUTE(unused) = saved_designs.emplace("$abc9_unmap", unmap_design);
+       log_assert(r.second);
 }
 
 void prep_xaiger(RTLIL::Module *module, bool dff)
@@ -208,17 +254,17 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
        dict<IdString, std::vector<IdString>> box_ports;
 
        for (auto cell : module->cells()) {
-               if (cell->type == ID($__ABC9_FF_))
+               if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
                        continue;
                if (cell->has_keep_attr())
                        continue;
 
-               auto inst_module = module->design->module(cell->type);
+               auto inst_module = design->module(cell->type);
                bool abc9_flop = inst_module && inst_module->get_bool_attribute(ID::abc9_flop);
                if (abc9_flop && !dff)
                        continue;
 
-               if ((inst_module && inst_module->get_bool_attribute(ID::abc9_box)) || abc9_flop) {
+               if (inst_module && inst_module->get_bool_attribute(ID::abc9_box)) {
                        auto r = box_ports.insert(cell->type);
                        if (r.second) {
                                // Make carry in the last PI, and carry out the last PO
@@ -305,15 +351,16 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
 
                cell->attributes[ID::abc9_box_seq] = box_count++;
 
-               IdString derived_type = box_module->derive(design, cell->parameters);
+               IdString derived_type;
+               if (cell->parameters.empty())
+                       derived_type = cell->type;
+               else
+                       derived_type = box_module->derive(design, cell->parameters);
                box_module = design->module(derived_type);
 
                auto r = cell_cache.insert(derived_type);
                auto &holes_cell = r.first->second;
                if (r.second) {
-                       if (box_module->has_processes())
-                               Pass::call_on_module(design, box_module, "proc");
-
                        if (box_module->get_bool_attribute(ID::whitebox)) {
                                holes_cell = holes_module->addCell(cell->name, derived_type);
 
@@ -342,21 +389,6 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
                                        else if (w->port_output)
                                                conn = holes_module->addWire(stringf("%s.%s", derived_type.c_str(), log_id(port_name)), GetSize(w));
                                }
-
-                               // For flops only, create an extra 1-bit input that drives a new wire
-                               //   called "<cell>.abc9_ff.Q" that is used below
-                               if (box_module->get_bool_attribute(ID::abc9_flop)) {
-                                       box_inputs++;
-                                       Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
-                                       if (!holes_wire) {
-                                               holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
-                                               holes_wire->port_input = true;
-                                               holes_wire->port_id = port_id++;
-                                               holes_module->ports.push_back(holes_wire->name);
-                                       }
-                                       Wire *Q = holes_module->addWire(stringf("%s.abc9_ff.Q", cell->name.c_str()));
-                                       holes_module->connect(Q, holes_wire);
-                               }
                        }
                        else // box_module is a blackbox
                                log_assert(holes_cell == nullptr);
@@ -394,7 +426,7 @@ void prep_delays(RTLIL::Design *design, bool dff_mode)
                }
 
                for (auto cell : module->cells()) {
-                       if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY)))
+                       if (cell->type.in(ID($_AND_), ID($_NOT_), ID($_DFF_N_), ID($_DFF_P_), ID($__ABC9_DELAY)))
                                continue;
 
                        RTLIL::Module* inst_module = module->design->module(cell->type);
@@ -540,7 +572,7 @@ void write_lut(RTLIL::Module *module, const std::string &dst) {
        ofs.close();
 }
 
-void prep_box(RTLIL::Design *design, bool dff_mode)
+void prep_box(RTLIL::Design *design)
 {
        TimingInfo timing;
 
@@ -555,165 +587,153 @@ void prep_box(RTLIL::Design *design, bool dff_mode)
 
        dict<IdString,std::vector<IdString>> box_ports;
        for (auto module : design->modules()) {
-               auto abc9_flop = module->get_bool_attribute(ID::abc9_flop);
-               if (abc9_flop) {
-                       auto r = module->attributes.insert(ID::abc9_box_id);
-                       if (!r.second)
-                               continue;
-                       r.first->second = abc9_box_id++;
-
-                       if (dff_mode) {
-                               int num_inputs = 0, num_outputs = 0;
-                               for (auto port_name : module->ports) {
-                                       auto wire = module->wire(port_name);
-                                       log_assert(GetSize(wire) == 1);
-                                       if (wire->port_input) num_inputs++;
-                                       if (wire->port_output) num_outputs++;
-                               }
-                               log_assert(num_outputs == 1);
+               if (!module->attributes.erase(ID::abc9_box))
+                       continue;
 
-                               ss << log_id(module) << " " << r.first->second.as_int();
-                               ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
-                               ss << " " << num_inputs+1 << " " << num_outputs << std::endl;
+               auto r = module->attributes.insert(ID::abc9_box_id);
+               if (!r.second)
+                       continue;
+               r.first->second = abc9_box_id++;
+
+               if (module->get_bool_attribute(ID::abc9_flop)) {
+                       int num_inputs = 0, num_outputs = 0;
+                       for (auto port_name : module->ports) {
+                               auto wire = module->wire(port_name);
+                               log_assert(GetSize(wire) == 1);
+                               if (wire->port_input) num_inputs++;
+                               if (wire->port_output) num_outputs++;
+                       }
+                       log_assert(num_outputs == 1);
 
-                               ss << "#";
-                               bool first = true;
-                               for (auto port_name : module->ports) {
-                                       auto wire = module->wire(port_name);
-                                       if (!wire->port_input)
-                                               continue;
-                                       if (first)
-                                               first = false;
-                                       else
-                                               ss << " ";
-                                       ss << log_id(wire);
-                               }
-                               ss << " abc9_ff.Q" << std::endl;
+                       ss << log_id(module) << " " << r.first->second.as_int();
+                       ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
+                       ss << " " << num_inputs << " " << num_outputs << std::endl;
 
-                               auto &t = timing.setup_module(module).required;
-                               first = true;
-                               for (auto port_name : module->ports) {
-                                       auto wire = module->wire(port_name);
-                                       if (!wire->port_input)
-                                               continue;
-                                       if (first)
-                                               first = false;
-                                       else
-                                               ss << " ";
-                                       log_assert(GetSize(wire) == 1);
-                                       auto it = t.find(TimingInfo::NameBit(port_name,0));
-                                       if (it == t.end())
-                                               // Assume that no setup time means zero
-                                               ss << 0;
-                                       else {
-                                               ss << it->second;
+                       ss << "#";
+                       bool first = true;
+                       for (auto port_name : module->ports) {
+                               auto wire = module->wire(port_name);
+                               if (!wire->port_input)
+                                       continue;
+                               if (first)
+                                       first = false;
+                               else
+                                       ss << " ";
+                               ss << log_id(wire);
+                       }
+                       ss << std::endl;
+
+                       auto &t = timing.setup_module(module).required;
+                       first = true;
+                       for (auto port_name : module->ports) {
+                               auto wire = module->wire(port_name);
+                               if (!wire->port_input)
+                                       continue;
+                               if (first)
+                                       first = false;
+                               else
+                                       ss << " ";
+                               log_assert(GetSize(wire) == 1);
+                               auto it = t.find(TimingInfo::NameBit(port_name,0));
+                               if (it == t.end())
+                                       // Assume that no setup time means zero
+                                       ss << 0;
+                               else {
+                                       ss << it->second;
 
 #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);
-                                               }
-#endif
+                                       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);
                                        }
-
+#endif
                                }
-                               // Last input is 'abc9_ff.Q'
-                               ss << " 0" << std::endl << std::endl;
-                               continue;
                        }
+                       ss << " # $_DFF_[NP]_.D" << std::endl;
+                       ss << std::endl;
                }
                else {
-                       if (!module->attributes.erase(ID::abc9_box))
-                               continue;
-
-                       auto r = module->attributes.insert(ID::abc9_box_id);
-                       if (!r.second)
-                               continue;
-                       r.first->second = abc9_box_id++;
-               }
+                       auto r2 = box_ports.insert(module->name);
+                       if (r2.second) {
+                               // Make carry in the last PI, and carry out the last PO
+                               //   since ABC requires it this way
+                               IdString carry_in, carry_out;
+                               for (const auto &port_name : module->ports) {
+                                       auto w = module->wire(port_name);
+                                       log_assert(w);
+                                       if (w->get_bool_attribute(ID::abc9_carry)) {
+                                               log_assert(w->port_input != w->port_output);
+                                               if (w->port_input)
+                                                       carry_in = port_name;
+                                               else if (w->port_output)
+                                                       carry_out = port_name;
+                                       }
+                                       else
+                                               r2.first->second.push_back(port_name);
+                               }
 
-               auto r = box_ports.insert(module->name);
-               if (r.second) {
-                       // Make carry in the last PI, and carry out the last PO
-                       //   since ABC requires it this way
-                       IdString carry_in, carry_out;
-                       for (const auto &port_name : module->ports) {
-                               auto w = module->wire(port_name);
-                               log_assert(w);
-                               if (w->get_bool_attribute(ID::abc9_carry)) {
-                                       log_assert(w->port_input != w->port_output);
-                                       if (w->port_input)
-                                               carry_in = port_name;
-                                       else if (w->port_output)
-                                               carry_out = port_name;
+                               if (carry_in != IdString()) {
+                                       r2.first->second.push_back(carry_in);
+                                       r2.first->second.push_back(carry_out);
                                }
-                               else
-                                       r.first->second.push_back(port_name);
                        }
 
-                       if (carry_in != IdString()) {
-                               r.first->second.push_back(carry_in);
-                               r.first->second.push_back(carry_out);
+                       std::vector<SigBit> inputs, outputs;
+                       for (auto port_name : r2.first->second) {
+                               auto wire = module->wire(port_name);
+                               if (wire->port_input)
+                                       for (int i = 0; i < GetSize(wire); i++)
+                                               inputs.emplace_back(wire, i);
+                               if (wire->port_output)
+                                       for (int i = 0; i < GetSize(wire); i++)
+                                               outputs.emplace_back(wire, i);
                        }
-               }
-
-               std::vector<SigBit> inputs;
-               std::vector<SigBit> outputs;
-               for (auto port_name : r.first->second) {
-                       auto wire = module->wire(port_name);
-                       if (wire->port_input)
-                               for (int i = 0; i < GetSize(wire); i++)
-                                       inputs.emplace_back(wire, i);
-                       if (wire->port_output)
-                               for (int i = 0; i < GetSize(wire); i++)
-                                       outputs.emplace_back(wire, i);
-               }
-
-               ss << log_id(module) << " " << module->attributes.at(ID::abc9_box_id).as_int();
-               ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
-               ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl;
-
-               bool first = true;
-               ss << "#";
-               for (const auto &i : inputs) {
-                       if (first)
-                               first = false;
-                       else
-                               ss << " ";
-                       if (GetSize(i.wire) == 1)
-                               ss << log_id(i.wire);
-                       else
-                               ss << log_id(i.wire) << "[" << i.offset << "]";
-               }
-               ss << std::endl;
 
-               auto &t = timing.setup_module(module).comb;
-               if (!abc9_flop && t.empty())
-                       log_warning("(* abc9_box *) module '%s' has no timing (and thus no connectivity) information.\n", log_id(module));
+                       ss << log_id(module) << " " << module->attributes.at(ID::abc9_box_id).as_int();
+                       ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
+                       ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl;
 
-               for (const auto &o : outputs) {
-                       first = true;
+                       bool first = true;
+                       ss << "#";
                        for (const auto &i : inputs) {
                                if (first)
                                        first = false;
                                else
                                        ss << " ";
-                               auto jt = t.find(TimingInfo::BitBit(i,o));
-                               if (jt == t.end())
-                                       ss << "-";
+                               if (GetSize(i.wire) == 1)
+                                       ss << log_id(i.wire);
                                else
-                                       ss << jt->second;
+                                       ss << log_id(i.wire) << "[" << i.offset << "]";
                        }
-                       ss << " # ";
-                       if (GetSize(o.wire) == 1)
-                               ss << log_id(o.wire);
-                       else
-                               ss << log_id(o.wire) << "[" << o.offset << "]";
                        ss << std::endl;
 
+                       auto &t = timing.setup_module(module).comb;
+                       if (t.empty())
+                               log_warning("(* abc9_box *) module '%s' has no timing (and thus no connectivity) information.\n", log_id(module));
+
+                       for (const auto &o : outputs) {
+                               first = true;
+                               for (const auto &i : inputs) {
+                                       if (first)
+                                               first = false;
+                                       else
+                                               ss << " ";
+                                       auto jt = t.find(TimingInfo::BitBit(i,o));
+                                       if (jt == t.end())
+                                               ss << "-";
+                                       else
+                                               ss << jt->second;
+                               }
+                               ss << " # ";
+                               if (GetSize(o.wire) == 1)
+                                       ss << log_id(o.wire);
+                               else
+                                       ss << log_id(o.wire) << "[" << o.offset << "]";
+                               ss << std::endl;
+                       }
+                       ss << std::endl;
                }
-               ss << std::endl;
        }
 
        // ABC expects at least one box
@@ -730,7 +750,7 @@ void write_box(RTLIL::Module *module, const std::string &dst) {
        ofs.close();
 }
 
-void reintegrate(RTLIL::Module *module)
+void reintegrate(RTLIL::Module *module, bool dff_mode)
 {
        auto design = module->design;
        log_assert(design);
@@ -783,7 +803,12 @@ void reintegrate(RTLIL::Module *module)
        for (auto cell : module->cells().to_vector()) {
                if (cell->has_keep_attr())
                        continue;
-               if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_)))
+
+               if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) {
+                       module->connect(cell->getPort(ID::Q), cell->getPort(ID::D));
+                       module->remove(cell);
+               }
+               else if (cell->type.in(ID($_AND_), ID($_NOT_)))
                        module->remove(cell);
                else if (cell->attributes.erase(ID::abc9_box_seq))
                        boxes.emplace_back(cell);
@@ -797,6 +822,16 @@ void reintegrate(RTLIL::Module *module)
        std::map<IdString, int> cell_stats;
        for (auto mapped_cell : mapped_mod->cells())
        {
+               if (dff_mode && mapped_cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) {
+                       SigBit D = mapped_cell->getPort(ID::D);
+                       SigBit Q = mapped_cell->getPort(ID::Q);
+                       if (D.wire)
+                               D.wire = module->wires_.at(remap_name(D.wire->name));
+                       Q.wire = module->wires_.at(remap_name(Q.wire->name));
+                       module->connect(Q, D);
+                       continue;
+               }
+
                // TODO: Speed up toposort -- we care about NOT ordering only
                toposort.node(mapped_cell->name);
 
@@ -846,7 +881,7 @@ void reintegrate(RTLIL::Module *module)
                        continue;
                }
 
-               if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) {
+               if (mapped_cell->type == ID($lut)) {
                        RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
                        cell->parameters = mapped_cell->parameters;
                        cell->attributes = mapped_cell->attributes;
@@ -893,7 +928,11 @@ void reintegrate(RTLIL::Module *module)
                        }
 
                        RTLIL::Module* box_module = design->module(existing_cell->type);
-                       IdString derived_type = box_module->derive(design, existing_cell->parameters);
+                       IdString derived_type;
+                       if (existing_cell->parameters.empty())
+                               derived_type = existing_cell->type;
+                       else
+                               derived_type = box_module->derive(design, existing_cell->parameters);
                        RTLIL::Module* derived_module = design->module(derived_type);
                        log_assert(derived_module);
                        log_assert(mapped_cell->type == stringf("$__boxid%d", derived_module->attributes.at(ID::abc9_box_id).as_int()));
@@ -1116,6 +1155,21 @@ struct Abc9OpsPass : public Pass {
                log("        check that the design is valid, e.g. (* abc9_box_id *) values are unique,\n");
                log("        (* abc9_carry *) is only given for one input/output port, etc.\n");
                log("\n");
+               log("    -prep_dff_hier\n");
+               log("        derive all cells with a type instantiating an (* abc9_flop *) module.\n");
+               log("        store such modules in named selection '$abc9_flops'.\n");
+               log("\n");
+               log("    -prep_dff_map\n");
+               log("        within (* abc9_flop *) modules, move all $specify{2,3}/$specrule cells\n");
+               log("        that share a 'DST' port with the $_DFF_[NP]_.Q port from this 'Q' port to\n");
+               log("        the DFF's 'D' port. this is to prepare such specify cells to be moved into\n");
+               log("        a submodule.\n");
+               log("\n");
+               log("    -prep_dff_unmap\n");
+               log("        create a new design '$abc9_unmap' containing techmap rules that map\n");
+               log("        *_$abc9_flop cells back into their original (* abc9_flop *) cells\n");
+               log("        (including their original parameters).\n");
+               log("\n");
                log("    -prep_delays\n");
                log("        insert `$__ABC9_DELAY' blackbox cells into the design to account for\n");
                log("        certain required times.\n");
@@ -1136,10 +1190,6 @@ struct Abc9OpsPass : public Pass {
                log("        consider flop cells (those instantiating modules marked with (* abc9_flop *))\n");
                log("        during -prep_{delays,xaiger,box}.\n");
                log("\n");
-               log("    -prep_dff\n");
-               log("        compute the clock domain and initial value of each flop in the design.\n");
-               log("        process the '$holes' module to support clock-enable functionality.\n");
-               log("\n");
                log("    -prep_lut <maxlut>\n");
                log("        pre-compute the lut library by analysing all modules marked with\n");
                log("        (* abc9_lut=<area> *).\n");
@@ -1167,7 +1217,7 @@ struct Abc9OpsPass : public Pass {
                bool check_mode = false;
                bool prep_delays_mode = false;
                bool mark_scc_mode = false;
-               bool prep_dff_mode = false;
+               bool prep_dff_hier_mode = false, prep_dff_map_mode = false, prep_dff_unmap_mode = false;
                bool prep_xaiger_mode = false;
                bool prep_lut_mode = false;
                bool prep_box_mode = false;
@@ -1177,53 +1227,71 @@ struct Abc9OpsPass : public Pass {
                int maxlut = 0;
                std::string write_box_dst;
 
+               bool valid = false;
                size_t argidx;
                for (argidx = 1; argidx < args.size(); argidx++) {
                        std::string arg = args[argidx];
                        if (arg == "-check") {
                                check_mode = true;
+                               valid = true;
                                continue;
                        }
                        if (arg == "-mark_scc") {
                                mark_scc_mode = true;
+                               valid = true;
+                               continue;
+                       }
+                       if (arg == "-prep_dff_hier") {
+                               prep_dff_hier_mode = true;
+                               valid = true;
                                continue;
                        }
-                       if (arg == "-prep_dff") {
-                               prep_dff_mode = true;
+                       if (arg == "-prep_dff_map") {
+                               prep_dff_map_mode = true;
+                               valid = true;
+                               continue;
+                       }
+                       if (arg == "-prep_dff_unmap") {
+                               prep_dff_unmap_mode = true;
+                               valid = true;
                                continue;
                        }
                        if (arg == "-prep_xaiger") {
                                prep_xaiger_mode = true;
+                               valid = true;
                                continue;
                        }
                        if (arg == "-prep_delays") {
                                prep_delays_mode = true;
+                               valid = true;
                                continue;
                        }
                        if (arg == "-prep_lut" && argidx+1 < args.size()) {
                                prep_lut_mode = true;
                                maxlut = atoi(args[++argidx].c_str());
-                               continue;
-                       }
-                       if (arg == "-maxlut" && argidx+1 < args.size()) {
+                               valid = true;
                                continue;
                        }
                        if (arg == "-write_lut" && argidx+1 < args.size()) {
                                write_lut_dst = args[++argidx];
                                rewrite_filename(write_lut_dst);
+                               valid = true;
                                continue;
                        }
                        if (arg == "-prep_box") {
                                prep_box_mode = true;
+                               valid = true;
                                continue;
                        }
                        if (arg == "-write_box" && argidx+1 < args.size()) {
                                write_box_dst = args[++argidx];
                                rewrite_filename(write_box_dst);
+                               valid = true;
                                continue;
                        }
                        if (arg == "-reintegrate") {
                                reintegrate_mode = true;
+                               valid = true;
                                continue;
                        }
                        if (arg == "-dff") {
@@ -1234,20 +1302,26 @@ struct Abc9OpsPass : public Pass {
                }
                extra_args(args, argidx, design);
 
-               if (!(check_mode || mark_scc_mode || prep_delays_mode || prep_xaiger_mode || prep_dff_mode || prep_lut_mode || prep_box_mode || !write_lut_dst.empty() || !write_box_dst.empty() || reintegrate_mode))
-                       log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff,lut,box}, -write_{lut,box}, -reintegrate must be specified.\n");
+               if (!valid)
+                       log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff[123],lut,box}, -write_{lut,box}, -reintegrate must be specified.\n");
 
-               if (dff_mode && !prep_delays_mode && !prep_xaiger_mode && !prep_box_mode)
-                       log_cmd_error("'-dff' option is only relevant for -prep_{delay,xaiger,box}.\n");
+               if (dff_mode && !prep_delays_mode && !prep_xaiger_mode && !reintegrate_mode)
+                       log_cmd_error("'-dff' option is only relevant for -prep_{delay,xaiger} or -reintegrate.\n");
 
                if (check_mode)
                        check(design);
+               if (prep_dff_hier_mode)
+                       prep_dff_hier(design);
+               if (prep_dff_map_mode)
+                       prep_dff_map(design);
+               if (prep_dff_unmap_mode)
+                       prep_dff_unmap(design);
                if (prep_delays_mode)
                        prep_delays(design, dff_mode);
                if (prep_lut_mode)
                        prep_lut(design, maxlut);
                if (prep_box_mode)
-                       prep_box(design, dff_mode);
+                       prep_box(design);
 
                for (auto mod : design->selected_modules()) {
                        if (mod->get_bool_attribute(ID::abc9_holes))
@@ -1267,12 +1341,10 @@ struct Abc9OpsPass : public Pass {
                                write_box(mod, write_box_dst);
                        if (mark_scc_mode)
                                mark_scc(mod);
-                       if (prep_dff_mode)
-                               prep_dff(mod);
                        if (prep_xaiger_mode)
                                prep_xaiger(mod, dff_mode);
                        if (reintegrate_mode)
-                               reintegrate(mod);
+                               reintegrate(mod, dff_mode);
                }
        }
 } Abc9OpsPass;
index c0c5dc2fda55bf3d81b96ea06eae85f8967ded99..9e8048fafc650d150048750e158a0312248d81a2 100644 (file)
@@ -1,6 +1,3 @@
-module \$__ABC9_FF_ (input D, output Q);
-endmodule
-
 (* abc9_box *)
 module \$__ABC9_DELAY (input I, output O);
   parameter DELAY = 0;
index 81f8a1d425ef123637d740748a62aec4e25721ea..1d733a650bf8e3dca6e79638064ea19b722c72c9 100644 (file)
 //   before invoking the `abc9` pass in order to transform the design into
 //   a format that it understands.
 
-`ifdef DFF_MODE
-// For example, (complex) flip-flops are expected to be described as an
-//   combinatorial box (containing all control logic such as clock enable
-//   or synchronous resets) followed by a basic D-Q flop.
-// Yosys will automatically analyse the simulation model (described in
-//   cells_sim.v) and detach any $_DFF_P_ or $_DFF_N_ cells present in
-//   order to extract the combinatorial control logic left behind.
-//   Specifically, a simulation model similar to the one below:
-//
-//                ++===================================++
-//                ||                        Sim model  ||
-//                ||      /\/\/\/\                     ||
-//            D -->>-----<        >     +------+       ||
-//            R -->>-----<  Comb. >     |$_DFF_|       ||
-//           CE -->>-----<  logic >-----| [NP]_|---+---->>-- Q
-//                ||  +--<        >     +------+   |   ||
-//                ||  |   \/\/\/\/                 |   ||
-//                ||  |                            |   ||
-//                ||  +----------------------------+   ||
-//                ||                                   ||
-//                ++===================================++
-//
-//   is transformed into:
-//
-//                ++==================++
-//                ||         Comb box ||
-//                ||                  ||
-//                ||      /\/\/\/\    ||
-//           D  -->>-----<        >   ||
-//           R  -->>-----<  Comb. >   ||        +-----------+
-//          CE  -->>-----<  logic >--->>-- $Q --|$__ABC9_FF_|--+-->> Q
-//   abc9_ff.Q +-->>-----<        >   ||        +-----------+  |
-//             |  ||      \/\/\/\/    ||                       |
-//             |  ||                  ||                       |
-//             |  ++==================++                       |
-//             |                                               |
-//             +-----------------------------------------------+
-//
-// The purpose of the following FD* rules are to wrap the flop with:
-// (a) a special $__ABC9_FF_ in front of the FD*'s output, indicating to abc9
-//     the connectivity of its basic D-Q flop
-// (b) an optional $__ABC9_ASYNC_ cell in front of $__ABC_FF_'s output to
-//     capture asynchronous behaviour
-// (c) a special abc9_ff.clock wire to capture its clock domain and polarity
-//     (indicated to `abc9' so that it only performs sequential synthesis
-//     (with reachability analysis) correctly on one domain at a time)
-// (d) an (* abc9_init *) attribute on the $__ABC9_FF_ cell capturing its
-//     initial state
-//     NOTE: in order to perform sequential synthesis, `abc9' requires that
-//     the initial value of all flops be zero
-// (e) a special _TECHMAP_REPLACE_.abc9_ff.Q wire that will be used for feedback
-//     into the (combinatorial) FD* cell to facilitate clock-enable behaviour
-
-module FDRE (output Q, (* techmap_autopurge *) input C, CE, D, R);
-  parameter [0:0] INIT = 1'b0;
-  parameter [0:0] IS_C_INVERTED = 1'b0;
-  parameter [0:0] IS_D_INVERTED = 1'b0;
-  parameter [0:0] IS_R_INVERTED = 1'b0;
-  wire QQ, $Q;
-  generate if (INIT == 1'b1) begin
-    assign Q = ~QQ;
-    FDSE #(
-      .INIT(1'b0),
-      .IS_C_INVERTED(IS_C_INVERTED),
-      .IS_D_INVERTED(IS_D_INVERTED),
-      .IS_S_INVERTED(IS_R_INVERTED)
-    ) _TECHMAP_REPLACE_ (
-      .D(~D), .Q($Q), .C(C), .CE(CE), .S(R)
-    );
-  end
-  else begin
-    assign Q = QQ;
-    FDRE #(
-      .INIT(1'b0),
-      .IS_C_INVERTED(IS_C_INVERTED),
-      .IS_D_INVERTED(IS_D_INVERTED),
-      .IS_R_INVERTED(IS_R_INVERTED)
-    ) _TECHMAP_REPLACE_ (
-      .D(D), .Q($Q), .C(C), .CE(CE), .R(R)
-    );
-  end
-  endgenerate
-  (* abc9_init = 1'b0 *)
-  $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
-
-  // Special signals
-  wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
-  wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
-endmodule
-module FDRE_1 (output Q, (* techmap_autopurge *) input C, CE, D, R);
-  parameter [0:0] INIT = 1'b0;
-  wire QQ, $Q;
-  generate if (INIT == 1'b1) begin
-    assign Q = ~QQ;
-    FDSE_1 #(
-      .INIT(1'b0)
-    ) _TECHMAP_REPLACE_ (
-      .D(~D), .Q($Q), .C(C), .CE(CE), .S(R)
-    );
-  end
-  else begin
-    assign Q = QQ;
-    FDRE_1 #(
-      .INIT(1'b0)
-    ) _TECHMAP_REPLACE_ (
-      .D(D), .Q($Q), .C(C), .CE(CE), .R(R)
-    );
-  end
-  endgenerate
-  (* abc9_init = 1'b0 *)
-  $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
-
-  // Special signals
-  wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
-  wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
-endmodule
-
-module FDSE (output Q, (* techmap_autopurge *) input C, CE, D, S);
-  parameter [0:0] INIT = 1'b1;
-  parameter [0:0] IS_C_INVERTED = 1'b0;
-  parameter [0:0] IS_D_INVERTED = 1'b0;
-  parameter [0:0] IS_S_INVERTED = 1'b0;
-  wire QQ, $Q;
-  generate if (INIT == 1'b1) begin
-    assign Q = ~QQ;
-    FDRE #(
-      .INIT(1'b0),
-      .IS_C_INVERTED(IS_C_INVERTED),
-      .IS_D_INVERTED(IS_D_INVERTED),
-      .IS_R_INVERTED(IS_S_INVERTED)
-    ) _TECHMAP_REPLACE_ (
-      .D(~D), .Q($Q), .C(C), .CE(CE), .R(S)
-    );
-  end
-  else begin
-    assign Q = QQ;
-    FDSE #(
-      .INIT(1'b0),
-      .IS_C_INVERTED(IS_C_INVERTED),
-      .IS_D_INVERTED(IS_D_INVERTED),
-      .IS_S_INVERTED(IS_S_INVERTED)
-    ) _TECHMAP_REPLACE_ (
-      .D(D), .Q($Q), .C(C), .CE(CE), .S(S)
-    );
-  end endgenerate
-  (* abc9_init = 1'b0 *)
-  $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
-
-  // Special signals
-  wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
-  wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
-endmodule
-module FDSE_1 (output Q, (* techmap_autopurge *) input C, CE, D, S);
-  parameter [0:0] INIT = 1'b1;
-  wire QQ, $Q;
-  generate if (INIT == 1'b1) begin
-    assign Q = ~QQ;
-    FDRE_1 #(
-      .INIT(1'b0)
-    ) _TECHMAP_REPLACE_ (
-      .D(~D), .Q($Q), .C(C), .CE(CE), .R(S)
-    );
-  end
-  else begin
-    assign Q = QQ;
-    FDSE_1 #(
-      .INIT(1'b0)
-    ) _TECHMAP_REPLACE_ (
-      .D(D), .Q($Q), .C(C), .CE(CE), .S(S)
-    );
-  end endgenerate
-  (* abc9_init = 1'b0 *)
-  $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
-
-  // Special signals
-  wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
-  wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
-endmodule
-
-module FDCE (output Q, (* techmap_autopurge *) input C, CE, D, CLR);
-  parameter [0:0] INIT = 1'b0;
-  parameter [0:0] IS_C_INVERTED = 1'b0;
-  parameter [0:0] IS_D_INVERTED = 1'b0;
-  parameter [0:0] IS_CLR_INVERTED = 1'b0;
-  wire QQ, $Q, $QQ;
-  generate if (INIT == 1'b1) begin
-    assign Q = ~QQ;
-    FDPE #(
-      .INIT(1'b0),
-      .IS_C_INVERTED(IS_C_INVERTED),
-      .IS_D_INVERTED(IS_D_INVERTED),
-      .IS_PRE_INVERTED(IS_CLR_INVERTED)
-    ) _TECHMAP_REPLACE_ (
-      .D(~D), .Q($Q), .C(C), .CE(CE), .PRE(CLR)
-                                        // ^^^ Note that async
-                                        //     control is not directly
-                                        //     supported by abc9 but its
-                                        //     behaviour is captured by
-                                        //     $__ABC9_ASYNC1 below
-    );
-    // Since this is an async flop, async behaviour is dealt with here
-    $__ABC9_ASYNC1 abc_async (.A($QQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ));
-  end
-  else begin
-    assign Q = QQ;
-    FDCE #(
-      .INIT(1'b0),
-      .IS_C_INVERTED(IS_C_INVERTED),
-      .IS_D_INVERTED(IS_D_INVERTED),
-      .IS_CLR_INVERTED(IS_CLR_INVERTED)
-    ) _TECHMAP_REPLACE_ (
-      .D(D), .Q($Q), .C(C), .CE(CE), .CLR(CLR)
-                                       // ^^^ Note that async
-                                       //     control is not directly
-                                       //     supported by abc9 but its
-                                       //     behaviour is captured by
-                                       //     $__ABC9_ASYNC0 below
-    );
-    // Since this is an async flop, async behaviour is dealt with here
-    $__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ));
-  end endgenerate
-  (* abc9_init = 1'b0 *)
-  $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
-
-  // Special signals
-  wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
-  wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
-endmodule
-module FDCE_1 (output Q, (* techmap_autopurge *) input C, CE, D, CLR);
-  parameter [0:0] INIT = 1'b0;
-  wire QQ, $Q, $QQ;
-  generate if (INIT == 1'b1) begin
-    assign Q = ~QQ;
-    FDPE_1 #(
-      .INIT(1'b0)
-    ) _TECHMAP_REPLACE_ (
-      .D(~D), .Q($Q), .C(C), .CE(CE), .PRE(CLR)
-                                        // ^^^ Note that async
-                                        //     control is not directly
-                                        //     supported by abc9 but its
-                                        //     behaviour is captured by
-                                        //     $__ABC9_ASYNC1 below
-    );
-    $__ABC9_ASYNC1 abc_async (.A($QQ), .S(CLR), .Y(QQ));
-  end
-  else begin
-    assign Q = QQ;
-    FDCE_1 #(
-      .INIT(1'b0)
-    ) _TECHMAP_REPLACE_ (
-      .D(D), .Q($Q), .C(C), .CE(CE), .CLR(CLR)
-                                       // ^^^ Note that async
-                                       //     control is not directly
-                                       //     supported by abc9 but its
-                                       //     behaviour is captured by
-                                       //     $__ABC9_ASYNC0 below
-    );
-    $__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR), .Y(QQ));
-  end endgenerate
-  (* abc9_init = 1'b0 *)
-  $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
-
-  // Special signals
-  wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
-  wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
-endmodule
-
-module FDPE (output Q, (* techmap_autopurge *) input C, CE, D, PRE);
-  parameter [0:0] INIT = 1'b1;
-  parameter [0:0] IS_C_INVERTED = 1'b0;
-  parameter [0:0] IS_D_INVERTED = 1'b0;
-  parameter [0:0] IS_PRE_INVERTED = 1'b0;
-  wire QQ, $Q, $QQ;
-  generate if (INIT == 1'b1) begin
-    assign Q = ~QQ;
-    FDCE #(
-      .INIT(1'b0),
-      .IS_C_INVERTED(IS_C_INVERTED),
-      .IS_D_INVERTED(IS_D_INVERTED),
-      .IS_CLR_INVERTED(IS_PRE_INVERTED),
-    ) _TECHMAP_REPLACE_ (
-      .D(~D), .Q($Q), .C(C), .CE(CE), .CLR(PRE)
-                                        // ^^^ Note that async
-                                        //     control is not directly
-                                        //     supported by abc9 but its
-                                        //     behaviour is captured by
-                                        //     $__ABC9_ASYNC0 below
-    );
-    $__ABC9_ASYNC0 abc_async (.A($QQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ));
-  end
-  else begin
-    assign Q = QQ;
-    FDPE #(
-      .INIT(1'b0),
-      .IS_C_INVERTED(IS_C_INVERTED),
-      .IS_D_INVERTED(IS_D_INVERTED),
-      .IS_PRE_INVERTED(IS_PRE_INVERTED),
-    ) _TECHMAP_REPLACE_ (
-      .D(D), .Q($Q), .C(C), .CE(CE), .PRE(PRE)
-                                       // ^^^ Note that async
-                                       //     control is not directly
-                                       //     supported by abc9 but its
-                                       //     behaviour is captured by
-                                       //     $__ABC9_ASYNC1 below
-    );
-    $__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ));
-  end endgenerate
-  (* abc9_init = 1'b0 *)
-  $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
-
-  // Special signals
-  wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
-  wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
-endmodule
-module FDPE_1 (output Q, (* techmap_autopurge *) input C, CE, D, PRE);
-  parameter [0:0] INIT = 1'b1;
-  wire QQ, $Q, $QQ;
-  generate if (INIT == 1'b1) begin
-    assign Q = ~QQ;
-    FDCE_1 #(
-      .INIT(1'b0)
-    ) _TECHMAP_REPLACE_ (
-      .D(~D), .Q($Q), .C(C), .CE(CE), .CLR(PRE)
-                                        // ^^^ Note that async
-                                        //     control is not directly
-                                        //     supported by abc9 but its
-                                        //     behaviour is captured by
-                                        //     $__ABC9_ASYNC0 below
-    );
-    $__ABC9_ASYNC0 abc_async (.A($QQ), .S(PRE), .Y(QQ));
-  end
-  else begin
-    assign Q = QQ;
-    FDPE_1 #(
-      .INIT(1'b0)
-    ) _TECHMAP_REPLACE_ (
-      .D(D), .Q($Q), .C(C), .CE(CE), .PRE(PRE)
-                                       // ^^^ Note that async
-                                       //     control is not directly
-                                       //     supported by abc9 but its
-                                       //     behaviour is captured by
-                                       //     $__ABC9_ASYNC1 below
-    );
-    $__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE), .Y(QQ));
-  end endgenerate
-  (* abc9_init = 1'b0 *)
-  $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
-
-  // Special signals
-  wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
-  wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
-endmodule
-`endif
-
 // Attach a (combinatorial) black-box onto the output
 //   of thes LUTRAM primitives to capture their
 //   asynchronous read behaviour
index 5604ceb0a5dcd83da651bcfe5ecead9585c27ba0..49a7bd88ca1a08bc0fede3ac34a242a657aa9901 100644 (file)
@@ -25,10 +25,6 @@ module $__ABC9_ASYNC01(input A, S, output Y);
   assign Y = A;
 endmodule
 
-module $__ABC9_FF_(input D, output Q);
-  assign Q = D;
-endmodule
-
 module $__ABC9_RAM6(input A, input [5:0] S, output Y);
   assign Y = A;
 endmodule
index 63223afbf48abe0fc9bac948a3f33032455ca4c8..93d080ffd8a7444f9842809d3ce2e85b5e9efe02 100644 (file)
@@ -640,7 +640,7 @@ module FDRSE (
       Q <= d;
 endmodule
 
-(* abc9_flop, lib_whitebox *)
+(* lib_whitebox *)
 module FDCE (
   output reg Q,
   (* clkbuf_sink *)
@@ -683,7 +683,7 @@ module FDCE (
   endspecify
 endmodule
 
-(* abc9_flop, lib_whitebox *)
+(* lib_whitebox *)
 module FDCE_1 (
   output reg Q,
   (* clkbuf_sink *)
@@ -708,7 +708,7 @@ module FDCE_1 (
   endspecify
 endmodule
 
-(* abc9_flop, lib_whitebox *)
+(* lib_whitebox *)
 module FDPE (
   output reg Q,
   (* clkbuf_sink *)
@@ -750,7 +750,7 @@ module FDPE (
   endspecify
 endmodule
 
-(* abc9_flop, lib_whitebox *)
+(* lib_whitebox *)
 module FDPE_1 (
   output reg Q,
   (* clkbuf_sink *)
index 229ffcb3d79bf898ae725c12446332ff4165a5d1..173bdcb91b63d0b95756fbb5916f9e189f01dea2 100644 (file)
@@ -613,10 +613,7 @@ struct SynthXilinxPass : public ScriptPass
                                if (family != "xc7")
                                        log_warning("'synth_xilinx -abc9' not currently supported for the '%s' family, "
                                                        "will use timing for 'xc7' instead.\n", family.c_str());
-                               std::string techmap_args = "-map +/xilinx/abc9_map.v -max_iter 1";
-                               if (dff_mode)
-                                       techmap_args += " -D DFF_MODE";
-                               run("techmap " + techmap_args);
+                               run("techmap -map +/xilinx/abc9_map.v -max_iter 1");
                                run("read_verilog -icells -lib -specify +/abc9_model.v +/xilinx/abc9_model.v");
                                std::string abc9_opts;
                                std::string k = "synth_xilinx.abc9.W";