Added ice40_ffinit pass
authorClifford Wolf <clifford@clifford.at>
Thu, 26 Nov 2015 17:11:06 +0000 (18:11 +0100)
committerClifford Wolf <clifford@clifford.at>
Thu, 26 Nov 2015 17:11:06 +0000 (18:11 +0100)
techlibs/ice40/Makefile.inc
techlibs/ice40/ice40_ffinit.cc [new file with mode: 0644]
techlibs/ice40/synth_ice40.cc

index 63d6086a7f895617f184bfa2b87ea3eaf99d064e..83009d1765b758d6cb9470f585271cf31c18aea9 100644 (file)
@@ -1,6 +1,7 @@
 
 OBJS += techlibs/ice40/synth_ice40.o
 OBJS += techlibs/ice40/ice40_ffssr.o
+OBJS += techlibs/ice40/ice40_ffinit.o
 OBJS += techlibs/ice40/ice40_opt.o
 
 GENFILES += techlibs/ice40/brams_init1.vh
diff --git a/techlibs/ice40/ice40_ffinit.cc b/techlibs/ice40/ice40_ffinit.cc
new file mode 100644 (file)
index 0000000..50400be
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ *  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 Ice40FfinitPass : public Pass {
+       Ice40FfinitPass() : Pass("ice40_ffinit", "iCE40: handle FF init values") { }
+       virtual void help()
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    ice40_ffinit [options] [selection]\n");
+               log("\n");
+               log("Remove zero init values for FF output signals. Add inverters to implement\n");
+               log("nonzero init values.\n");
+               log("\n");
+       }
+       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       {
+               log_header("Executing ICE40_FFINIT pass (implement FF init values).\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);
+
+               for (auto module : design->selected_modules())
+               {
+                       log("Handling FF init values in %s.\n", log_id(module));
+
+                       SigMap sigmap(module);
+                       pool<Wire*> init_wires;
+                       dict<SigBit, State> initbits;
+                       pool<SigBit> handled_initbits;
+
+                       for (auto wire : module->selected_wires())
+                       {
+                               if (wire->attributes.count("\\init") == 0)
+                                       continue;
+
+                               SigSpec wirebits = sigmap(wire);
+                               Const initval = wire->attributes.at("\\init");
+                               init_wires.insert(wire);
+
+                               for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++)
+                               {
+                                       SigBit bit = wirebits[i];
+                                       State val = initval[i];
+
+                                       if (val != State::S0 && val != State::S1)
+                                               continue;
+
+                                       if (initbits.count(bit)) {
+                                               if (initbits.at(bit) != val)
+                                                       log_error("Conflicting init values for signal %s.\n", log_signal(bit));
+                                               continue;
+                                       }
+
+                                       initbits[bit] = val;
+                               }
+                       }
+
+                       for (auto cell : module->selected_cells())
+                       {
+                               if (!cell->type.in("\\SB_DFF", "\\SB_DFFE", "\\SB_DFFN", "\\SB_DFFNE"))
+                                       continue;
+
+                               SigBit sig_d = sigmap(cell->getPort("\\D"));
+                               SigBit sig_q = sigmap(cell->getPort("\\Q"));
+
+                               if (!initbits.count(sig_q))
+                                       continue;
+
+                               State val = initbits.at(sig_q);
+                               handled_initbits.insert(sig_q);
+
+                               log("FF init value for cell %s (%s): %s = %c\n", log_id(cell), log_id(cell->type),
+                                               log_signal(sig_q), val != State::S0 ? '1' : '0');
+
+                               if (val == State::S0)
+                                       continue;
+
+                               Wire *new_sig_d = module->addWire(NEW_ID);
+                               Wire *new_sig_q = module->addWire(NEW_ID);
+
+                               module->addNotGate(NEW_ID, sig_d, new_sig_d);
+                               module->addNotGate(NEW_ID, new_sig_q, sig_q);
+
+                               cell->setPort("\\D", new_sig_d);
+                               cell->setPort("\\Q", new_sig_q);
+                       }
+
+                       for (auto wire : init_wires)
+                       {
+                               if (wire->attributes.count("\\init") == 0)
+                                       continue;
+
+                               SigSpec wirebits = sigmap(wire);
+                               Const &initval = wire->attributes.at("\\init");
+                               bool remove_attribute = true;
+
+                               for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) {
+                                       if (handled_initbits.count(wirebits[i]))
+                                               wirebits[i] = State::Sx;
+                                       else
+                                               remove_attribute = false;
+                               }
+
+                               if (remove_attribute)
+                                       wire->attributes.erase("\\init");
+                       }
+               }
+       }
+} Ice40FfinitPass;
+
+PRIVATE_NAMESPACE_END
index 788835f1d3bc28a4d97e4c605281e5eedc724087..75cab7bda8b57796f36fc74c74931a1cab4397dd 100644 (file)
@@ -104,6 +104,7 @@ struct SynthIce40Pass : public Pass {
                log("        techmap -map +/ice40/cells_map.v\n");
                log("        opt_const -mux_undef\n");
                log("        simplemap\n");
+               log("        ice40_ffinit\n");
                log("        ice40_ffssr\n");
                log("        ice40_opt -full\n");
                log("\n");
@@ -236,6 +237,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_ffinit");
                        Pass::call(design, "ice40_ffssr");
                        Pass::call(design, "ice40_opt -full");
                }