Added mapping of synchronous set/reset to iCE40 flow
authorClifford Wolf <clifford@clifford.at>
Fri, 17 Apr 2015 09:54:25 +0000 (11:54 +0200)
committerClifford Wolf <clifford@clifford.at>
Fri, 17 Apr 2015 09:54:25 +0000 (11:54 +0200)
techlibs/ice40/Makefile.inc
techlibs/ice40/ice40_ffssr.cc [new file with mode: 0644]
techlibs/ice40/synth_ice40.cc

index 08a24d92f26d12a3772e7456ccb5eeb18a317d4c..6e556ab888fe0f426b592ea10ab7229ded568ed5 100644 (file)
@@ -1,5 +1,6 @@
 
 OBJS += techlibs/ice40/synth_ice40.o
+OBJS += techlibs/ice40/ice40_ffssr.o
 
 $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_map.v))
 $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_sim.v))
diff --git a/techlibs/ice40/ice40_ffssr.cc b/techlibs/ice40/ice40_ffssr.cc
new file mode 100644 (file)
index 0000000..4159d85
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *  
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct Ice40FfssrPass : public Pass {
+       Ice40FfssrPass() : Pass("ice40_ffssr", "iCE40: merge synchronous set/reset into FF cells") { }
+       virtual void help()
+       {
+               log("\n");
+               log("    ice40_ffssr [options] [selection]\n");
+               log("\n");
+               log("Merge synchronous set/reset $_MUX_ cells into iCE40 FFs.\n");
+               log("\n");
+       }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing ICE40_FFSSR pass (merge synchronous set/reset into FF cells).\n");
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++)
+               {
+                       // if (args[argidx] == "-singleton") {
+                       //      singleton_mode = true;
+                       //      continue;
+                       // }
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               pool<IdString> sb_dff_types;
+               sb_dff_types.insert("\\SB_DFF");
+               sb_dff_types.insert("\\SB_DFFE");
+               sb_dff_types.insert("\\SB_DFFN");
+               sb_dff_types.insert("\\SB_DFFNE");
+
+               for (auto module : design->selected_modules())
+               {
+                       log("Merging set/reset $_MUX_ cells into SB_FFs in %s.\n", log_id(module));
+
+                       SigMap sigmap(module);
+                       dict<SigBit, Cell*> sr_muxes;
+                       vector<Cell*> ff_cells;
+
+                       for (auto cell : module->selected_cells())
+                       {
+                               if (sb_dff_types.count(cell->type)) {
+                                       ff_cells.push_back(cell);
+                                       continue;
+                               }
+
+                               if (cell->type != "$_MUX_")
+                                       continue;
+
+                               SigBit bit_a = sigmap(cell->getPort("\\A"));
+                               SigBit bit_b = sigmap(cell->getPort("\\B"));
+
+                               if (bit_a.wire == nullptr || bit_b.wire == nullptr)
+                                       sr_muxes[sigmap(cell->getPort("\\Y"))] = cell;
+                       }
+
+                       for (auto cell : ff_cells)
+                       {
+                               SigBit bit_d = sigmap(cell->getPort("\\D"));
+
+                               if (sr_muxes.count(bit_d) == 0)
+                                       continue;
+
+                               Cell *mux_cell = sr_muxes.at(bit_d);
+                               SigBit bit_a = sigmap(mux_cell->getPort("\\A"));
+                               SigBit bit_b = sigmap(mux_cell->getPort("\\B"));
+                               SigBit bit_s = sigmap(mux_cell->getPort("\\S"));
+
+                               log("  Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell),
+                                               log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type));
+
+                               SigBit sr_val, sr_sig;
+                               if (bit_a.wire == nullptr) {
+                                       bit_d = bit_b;
+                                       sr_val = bit_a;
+                                       sr_sig = module->NotGate(NEW_ID, bit_s);
+                               } else {
+                                       log_assert(bit_b.wire == nullptr);
+                                       bit_d = bit_a;
+                                       sr_val = bit_b;
+                                       sr_sig = bit_s;
+                               }
+
+                               if (sr_val == State::S1) {
+                                       cell->type = cell->type.str() + "SS";
+                                       cell->setPort("\\S", sr_sig);
+                                       cell->setPort("\\D", bit_d);
+                               } else {
+                                       cell->type = cell->type.str() + "SR";
+                                       cell->setPort("\\R", sr_sig);
+                                       cell->setPort("\\D", bit_d);
+                               }
+                       }
+               }
+       }
+} Ice40FfssrPass;
+PRIVATE_NAMESPACE_END
index c5d8f5edbd563c27b106ff548eff83caa8741688..1d23cd954e03ea2edb99b159a0db9b2e3087c0a5 100644 (file)
@@ -63,9 +63,9 @@ struct SynthIce40Pass : public Pass {
                log("        synth -run coarse\n");
                log("\n");
                log("    fine:\n");
-               log("        opt -fast -full\n");
+               log("        opt -fast -mux_undef -undriven -fine\n");
                log("        memory_map\n");
-               log("        opt -full\n");
+               log("        opt -undriven -fine\n");
                log("        techmap\n");
                log("        opt -fast\n");
                log("\n");
@@ -74,6 +74,7 @@ struct SynthIce40Pass : public Pass {
                log("        techmap -map +/ice40/cells_map.v\n");
                log("        opt_const -mux_undef\n");
                log("        simplemap\n");
+               log("        ice40_ffssr\n");
                log("        clean\n");
                log("\n");
                log("    map_luts:\n");
@@ -135,9 +136,9 @@ struct SynthIce40Pass : public Pass {
 
                if (check_label(active, run_from, run_to, "fine"))
                {
-                       Pass::call(design, "opt -fast -full");
+                       Pass::call(design, "opt -fast -mux_undef -undriven -fine");
                        Pass::call(design, "memory_map");
-                       Pass::call(design, "opt -full");
+                       Pass::call(design, "opt -undriven -fine");
                        Pass::call(design, "techmap");
                        Pass::call(design, "opt -fast");
                }
@@ -148,6 +149,7 @@ struct SynthIce40Pass : public Pass {
                        Pass::call(design, "techmap -map +/ice40/cells_map.v");
                        Pass::call(design, "opt_const -mux_undef");
                        Pass::call(design, "simplemap");
+                       Pass::call(design, "ice40_ffssr");
                        Pass::call(design, "clean");
                }