Add clock buffer insertion pass, improve iopadmap.
authorMarcin Kościelnicki <koriakin@0x04.net>
Mon, 12 Aug 2019 15:57:43 +0000 (15:57 +0000)
committerMarcin Kościelnicki <koriakin@0x04.net>
Mon, 12 Aug 2019 22:16:38 +0000 (00:16 +0200)
A few new attributes are defined for use in cell libraries:

- iopad_external_pin: marks PAD cell's external-facing pin.  Pad
  insertion will be skipped for ports that are already connected
  to such a pin.
- clkbuf_sink: marks an input pin as a clock pin, requesting clock
  buffer insertion.
- clkbuf_driver: marks an output pin as a clock buffer output pin.
  Clock buffer insertion will be skipped for nets that are already
  driven by such a pin.

All three are module attributes that should be set to a comma-separeted
list of pin names.

Clock buffer insertion itself works as follows:

1. All cell ports, starting from bottom up, can be marked as clock sinks
   (requesting clock buffer insertion) or as clock buffer outputs.
2. If a wire in a given module is driven by a cell port that is a clock
   buffer output, it is in turn also considered a clock buffer output.
3. If an input port in a non-top module is connected to a clock sink in a
   contained cell, it is also in turn considered a clock sink.
4. If a wire in a module is driven by a non-clock-buffer cell, and is
   also connected to a clock sink port in a contained cell, a clock
   buffer is inserted in this module.
5. For the top module, a clock buffer is also inserted on input ports
   connected to clock sinks, optionally with a special kind of input
   PAD (such as IBUFG for Xilinx).
6. Clock buffer insertion on a given wire is skipped if the clkbuf_inhibit
   attribute is set on it.

examples/mimas2/run_yosys.ys
passes/techmap/Makefile.inc
passes/techmap/clkbufmap.cc [new file with mode: 0644]
passes/techmap/iopadmap.cc
techlibs/xilinx/cells_sim.v
techlibs/xilinx/cells_xtra.sh
techlibs/xilinx/cells_xtra.v
techlibs/xilinx/synth_xilinx.cc
techlibs/xilinx/xc6s_brams_bb.v
techlibs/xilinx/xc7_brams_bb.v

index b3204b1caa23a9e15b8208e4acee1bc9c817e327..b48877811cc32a8bbad7409d672a4aeb96ffccc1 100644 (file)
@@ -1,4 +1,3 @@
 read_verilog example.v
-synth_xilinx -top example -family xc6s
-iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I
+synth_xilinx -top example -family xc6s -ise
 write_edif -pvector bra example.edif
index 56f05eca42e5efc8ec94113e43a1b54dec33f579..631a80aa5e34c12b68746e47b6abbffe976fa3ce 100644 (file)
@@ -16,6 +16,7 @@ endif
 
 ifneq ($(SMALL),1)
 OBJS += passes/techmap/iopadmap.o
+OBJS += passes/techmap/clkbufmap.o
 OBJS += passes/techmap/hilomap.o
 OBJS += passes/techmap/extract.o
 OBJS += passes/techmap/extract_fa.o
diff --git a/passes/techmap/clkbufmap.cc b/passes/techmap/clkbufmap.cc
new file mode 100644 (file)
index 0000000..9ecc830
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ *  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
+
+void split_portname_pair(std::string &port1, std::string &port2)
+{
+       size_t pos = port1.find_first_of(':');
+       if (pos != std::string::npos) {
+               port2 = port1.substr(pos+1);
+               port1 = port1.substr(0, pos);
+       }
+}
+
+std::vector<std::string> split(std::string text, const char *delim)
+{
+       std::vector<std::string> list;
+       char *p = strdup(text.c_str());
+       char *t = strtok(p, delim);
+       while (t != NULL) {
+               list.push_back(t);
+               t = strtok(NULL, delim);
+       }
+       free(p);
+       return list;
+}
+
+struct ClkbufmapPass : public Pass {
+       ClkbufmapPass() : Pass("clkbufmap", "insert global buffers on clock networks") { }
+       void help() YS_OVERRIDE
+       {
+               log("\n");
+               log("    clkbufmap [options] [selection]\n");
+               log("\n");
+               log("Inserts global buffers between nets connected to clock inputs and their\n");
+               log("drivers.\n");
+               log("\n");
+               log("    -buf <celltype> <portname_out>:<portname_in>\n");
+               log("        Specifies the cell type to use for the global buffers\n");
+               log("        and its port names.  The first port will be connected to\n");
+               log("        the clock network sinks, and the second will be connected\n");
+               log("        to the actual clock source.  This option is required.\n");
+               log("\n");
+               log("    -inpad <celltype> <portname_out>:<portname_in>\n");
+               log("        If specified, a PAD cell of the given type is inserted on\n");
+               log("        clock nets that are also top module's inputs (in addition\n");
+               log("        to the global buffer).\n");
+               log("\n");
+       }
+
+       void module_queue(Design *design, Module *module, std::vector<Module *> &modules_sorted, pool<Module *> &modules_processed) {
+               if (modules_processed.count(module))
+                       return;
+               for (auto cell : module->cells()) {
+                       Module *submodule = design->module(cell->type);
+                       if (!submodule)
+                               continue;
+                       module_queue(design, submodule, modules_sorted, modules_processed);
+               }
+               modules_sorted.push_back(module);
+               modules_processed.insert(module);
+       }
+
+       void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+       {
+               log_header(design, "Executing CLKBUFMAP pass (inserting global clock buffers).\n");
+
+               std::string buf_celltype, buf_portname, buf_portname2;
+               std::string inpad_celltype, inpad_portname, inpad_portname2;
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++)
+               {
+                       std::string arg = args[argidx];
+                       if (arg == "-buf" && argidx+2 < args.size()) {
+                               buf_celltype = args[++argidx];
+                               buf_portname = args[++argidx];
+                               split_portname_pair(buf_portname, buf_portname2);
+                               continue;
+                       }
+                       if (arg == "-inpad" && argidx+2 < args.size()) {
+                               inpad_celltype = args[++argidx];
+                               inpad_portname = args[++argidx];
+                               split_portname_pair(inpad_portname, inpad_portname2);
+                               continue;
+                       }
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               if (buf_celltype.empty())
+                       log_error("The -buf option is required.");
+
+               // Cell type, port name, bit index.
+               pool<pair<IdString, pair<IdString, int>>> sink_ports;
+               pool<pair<IdString, pair<IdString, int>>> buf_ports;
+
+               // Process submodules before module using them.
+               std::vector<Module *> modules_sorted;
+               pool<Module *> modules_processed;
+               for (auto module : design->selected_modules())
+                       module_queue(design, module, modules_sorted, modules_processed);
+
+               for (auto module : modules_sorted)
+               {
+                       if (module->get_blackbox_attribute()) {
+                               auto it = module->attributes.find("\\clkbuf_driver");
+                               if (it != module->attributes.end()) {
+                                       auto value = it->second.decode_string();
+                                       for (auto name : split(value, ",")) {
+                                               auto wire = module->wire(RTLIL::escape_id(name));
+                                               if (!wire)
+                                                       log_error("Module %s does not have port %s.\n", log_id(module), log_id(name));
+                                               for (int i = 0; i < GetSize(wire); i++)
+                                                       buf_ports.insert(make_pair(module->name, make_pair(RTLIL::escape_id(name), i)));
+                                       }
+                               }
+                               it = module->attributes.find("\\clkbuf_sink");
+                               if (it != module->attributes.end()) {
+                                       auto value = it->second.decode_string();
+                                       for (auto name : split(value, ",")) {
+                                               auto wire = module->wire(RTLIL::escape_id(name));
+                                               if (!wire)
+                                                       log_error("Module %s does not have port %s.\n", log_id(module), log_id(name));
+                                               for (int i = 0; i < GetSize(wire); i++)
+                                                       sink_ports.insert(make_pair(module->name, make_pair(RTLIL::escape_id(name), i)));
+                                       }
+                               }
+                               continue;
+                       }
+                       pool<SigBit> sink_wire_bits;
+                       pool<SigBit> buf_wire_bits;
+                       pool<SigBit> driven_wire_bits;
+                       SigMap sigmap(module);
+                       // bit -> (buffer, buffer's input)
+                       dict<SigBit, pair<Cell *, Wire *>> buffered_bits;
+
+                       // First, collect nets that could use a clock buffer.
+                       for (auto cell : module->cells())
+                       for (auto port : cell->connections())
+                       for (int i = 0; i < port.second.size(); i++)
+                               if (sink_ports.count(make_pair(cell->type, make_pair(port.first, i))))
+                                       sink_wire_bits.insert(sigmap(port.second[i]));
+
+                       // Second, collect ones that already have a clock buffer.
+                       for (auto cell : module->cells())
+                       for (auto port : cell->connections())
+                       for (int i = 0; i < port.second.size(); i++)
+                               if (buf_ports.count(make_pair(cell->type, make_pair(port.first, i))))
+                                       buf_wire_bits.insert(sigmap(port.second[i]));
+
+                       // Collect all driven bits.
+                       for (auto cell : module->cells())
+                       for (auto port : cell->connections())
+                               if (cell->output(port.first))
+                                       for (int i = 0; i < port.second.size(); i++)
+                                               driven_wire_bits.insert(port.second[i]);
+
+                       // Insert buffers.
+                       std::vector<pair<Wire *, Wire *>> input_queue;
+                       for (auto wire : module->selected_wires())
+                       {
+                               // Should not happen.
+                               if (wire->port_input && wire->port_output)
+                                       continue;
+                               if (wire->get_bool_attribute("\\clkbuf_inhibit"))
+                                       continue;
+
+                               pool<int> input_bits;
+
+                               for (int i = 0; i < GetSize(wire); i++)
+                               {
+                                       SigBit wire_bit(wire, i);
+                                       SigBit mapped_wire_bit = sigmap(wire_bit);
+                                       if (buf_wire_bits.count(mapped_wire_bit)) {
+                                               // Already buffered downstream.  If this is an output, mark it.
+                                               if (wire->port_output)
+                                                       buf_ports.insert(make_pair(module->name, make_pair(wire->name, i)));
+                                       } else if (!sink_wire_bits.count(mapped_wire_bit)) {
+                                               // Nothing to do.
+                                       } else if (driven_wire_bits.count(wire_bit) || (wire->port_input && module->get_bool_attribute("\\top"))) {
+                                               // Clock network not yet buffered, driven by one of
+                                               // our cells or a top-level input -- buffer it.
+
+                                               log("Inserting %s on %s.%s[%d].\n", buf_celltype.c_str(), log_id(module), log_id(wire), i);
+                                               RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(buf_celltype));
+                                               Wire *iwire = module->addWire(NEW_ID);
+                                               cell->setPort(RTLIL::escape_id(buf_portname), mapped_wire_bit);
+                                               cell->setPort(RTLIL::escape_id(buf_portname2), iwire);
+                                               if (wire->port_input && !inpad_celltype.empty() && module->get_bool_attribute("\\top")) {
+                                                       log("Inserting %s on %s.%s[%d].\n", inpad_celltype.c_str(), log_id(module), log_id(wire), i);
+                                                       RTLIL::Cell *cell2 = module->addCell(NEW_ID, RTLIL::escape_id(inpad_celltype));
+                                                       cell2->setPort(RTLIL::escape_id(inpad_portname), iwire);
+                                                       iwire = module->addWire(NEW_ID);
+                                                       cell2->setPort(RTLIL::escape_id(inpad_portname2), iwire);
+                                               }
+                                               buffered_bits[mapped_wire_bit] = make_pair(cell, iwire);
+
+                                               if (wire->port_input) {
+                                                       input_bits.insert(i);
+                                               }
+                                       } else if (wire->port_input) {
+                                               // A clock input in a submodule -- mark it, let higher level
+                                               // worry about it.
+                                               if (wire->port_input)
+                                                       sink_ports.insert(make_pair(module->name, make_pair(wire->name, i)));
+                                       }
+                               }
+                               if (!input_bits.empty()) {
+                                       // This is an input port and some buffers were inserted -- we need
+                                       // to create a new input wire and transfer attributes.
+                                       Wire *new_wire = module->addWire(NEW_ID, wire);
+
+                                       for (int i = 0; i < wire->width; i++) {
+                                               SigBit wire_bit(wire, i);
+                                               SigBit mapped_wire_bit = sigmap(wire_bit);
+                                               auto it = buffered_bits.find(mapped_wire_bit);
+                                               if (it != buffered_bits.end()) {
+
+                                                       module->connect(it->second.second, SigSpec(new_wire, i));
+                                               } else {
+                                                       module->connect(SigSpec(wire, i), SigSpec(new_wire, i));
+                                               }
+                                       }
+                                       input_queue.push_back(make_pair(wire, new_wire));
+                               }
+                       }
+
+                       // Mark any newly-buffered output ports as such.
+                       for (auto wire : module->selected_wires()) {
+                               if (wire->port_input || !wire->port_output)
+                                       continue;
+                               for (int i = 0; i < GetSize(wire); i++)
+                               {
+                                       SigBit wire_bit(wire, i);
+                                       SigBit mapped_wire_bit = sigmap(wire_bit);
+                                       if (buffered_bits.count(mapped_wire_bit))
+                                               buf_ports.insert(make_pair(module->name, make_pair(wire->name, i)));
+                               }
+                       }
+
+                       // Reconnect the drivers to buffer inputs.
+                       for (auto cell : module->cells())
+                       for (auto port : cell->connections()) {
+                               if (!cell->output(port.first))
+                                       continue;
+                               SigSpec sig = port.second;
+                               bool newsig = false;
+                               for (auto &bit : sig) {
+                                       const auto it = buffered_bits.find(sigmap(bit));
+                                       if (it == buffered_bits.end())
+                                               continue;
+                                       // Avoid substituting buffer's own output pin.
+                                       if (cell == it->second.first)
+                                               continue;
+                                       bit = it->second.second;
+                                       newsig = true;
+                               }
+                               if (newsig)
+                                       cell->setPort(port.first, sig);
+                       }
+
+                       // This has to be done last, to avoid upsetting sigmap before the port reconnections.
+                       for (auto &it : input_queue) {
+                               Wire *wire = it.first;
+                               Wire *new_wire = it.second;
+                               module->swap_names(new_wire, wire);
+                               wire->attributes.clear();
+                               wire->port_id = 0;
+                               wire->port_input = false;
+                               wire->port_output = false;
+                       }
+
+                       module->fixup_ports();
+               }
+       }
+} ClkbufmapPass;
+
+PRIVATE_NAMESPACE_END
index efcc082d55f253cb34386080c90752f2f14d5cb3..e3d68ab0cab97d79b3a1b35a150f97c0d493d7e3 100644 (file)
@@ -32,6 +32,19 @@ void split_portname_pair(std::string &port1, std::string &port2)
        }
 }
 
+std::vector<std::string> split(std::string text, const char *delim)
+{
+       std::vector<std::string> list;
+       char *p = strdup(text.c_str());
+       char *t = strtok(p, delim);
+       while (t != NULL) {
+               list.push_back(t);
+               t = strtok(NULL, delim);
+       }
+       free(p);
+       return list;
+}
+
 struct IopadmapPass : public Pass {
        IopadmapPass() : Pass("iopadmap", "technology mapping of i/o pads (or buffers)") { }
        void help() YS_OVERRIDE
@@ -64,6 +77,11 @@ struct IopadmapPass : public Pass {
                log("        of the tristate driver and the 2nd portname is the internal output\n");
                log("        buffering the external signal.\n");
                log("\n");
+               log("    -ignore <celltype> <portname>[:<portname>]*\n");
+               log("        Skips mapping inputs/outputs that are already connected to given\n");
+               log("        ports of the given cell.  Can be used multiple times.  This is in\n");
+               log("        addition to the cells specified as mapping targets.\n");
+               log("\n");
                log("    -widthparam <param_name>\n");
                log("        Use the specified parameter name to set the port width.\n");
                log("\n");
@@ -88,6 +106,7 @@ struct IopadmapPass : public Pass {
                std::string toutpad_celltype, toutpad_portname, toutpad_portname2, toutpad_portname3;
                std::string tinoutpad_celltype, tinoutpad_portname, tinoutpad_portname2, tinoutpad_portname3, tinoutpad_portname4;
                std::string widthparam, nameparam;
+               pool<pair<IdString, IdString>> ignore;
                bool flag_bits = false;
 
                size_t argidx;
@@ -127,6 +146,18 @@ struct IopadmapPass : public Pass {
                                split_portname_pair(tinoutpad_portname3, tinoutpad_portname4);
                                continue;
                        }
+                       if (arg == "-ignore" && argidx+2 < args.size()) {
+                               std::string ignore_celltype = args[++argidx];
+                               std::string ignore_portname = args[++argidx];
+                               std::string ignore_portname2;
+                               while (!ignore_portname.empty()) {
+                                       split_portname_pair(ignore_portname, ignore_portname2);
+                                       ignore.insert(make_pair(RTLIL::escape_id(ignore_celltype), RTLIL::escape_id(ignore_portname)));
+
+                                       ignore_portname = ignore_portname2;
+                               }
+                               continue;
+                       }
                        if (arg == "-widthparam" && argidx+1 < args.size()) {
                                widthparam = args[++argidx];
                                continue;
@@ -143,6 +174,28 @@ struct IopadmapPass : public Pass {
                }
                extra_args(args, argidx, design);
 
+               if (!inpad_portname2.empty())
+                       ignore.insert(make_pair(RTLIL::escape_id(inpad_celltype), RTLIL::escape_id(inpad_portname2)));
+               if (!outpad_portname2.empty())
+                       ignore.insert(make_pair(RTLIL::escape_id(outpad_celltype), RTLIL::escape_id(outpad_portname2)));
+               if (!inoutpad_portname2.empty())
+                       ignore.insert(make_pair(RTLIL::escape_id(inoutpad_celltype), RTLIL::escape_id(inoutpad_portname2)));
+               if (!toutpad_portname3.empty())
+                       ignore.insert(make_pair(RTLIL::escape_id(toutpad_celltype), RTLIL::escape_id(toutpad_portname3)));
+               if (!tinoutpad_portname4.empty())
+                       ignore.insert(make_pair(RTLIL::escape_id(tinoutpad_celltype), RTLIL::escape_id(tinoutpad_portname4)));
+
+               for (auto module : design->modules())
+               {
+                       auto it = module->attributes.find("\\iopad_external_pin");
+                       if (it != module->attributes.end()) {
+                               auto value = it->second.decode_string();
+                               for (auto name : split(value, ",")) {
+                                       ignore.insert(make_pair(module->name, RTLIL::escape_id(name)));
+                               }
+                       }
+               }
+
                for (auto module : design->selected_modules())
                {
                        dict<IdString, pool<int>> skip_wires;
@@ -150,28 +203,11 @@ struct IopadmapPass : public Pass {
                        SigMap sigmap(module);
 
                        for (auto cell : module->cells())
-                       {
-                               if (cell->type == RTLIL::escape_id(inpad_celltype) && cell->hasPort(RTLIL::escape_id(inpad_portname2)))
-                                       for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inpad_portname2))))
-                                               skip_wire_bits.insert(bit);
-
-                               if (cell->type == RTLIL::escape_id(outpad_celltype) && cell->hasPort(RTLIL::escape_id(outpad_portname2)))
-                                       for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(outpad_portname2))))
-                                               skip_wire_bits.insert(bit);
-
-                               if (cell->type == RTLIL::escape_id(inoutpad_celltype) && cell->hasPort(RTLIL::escape_id(inoutpad_portname2)))
-                                       for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inoutpad_portname2))))
+                       for (auto port : cell->connections())
+                               if (ignore.count(make_pair(cell->type, port.first)))
+                                       for (auto bit : sigmap(port.second))
                                                skip_wire_bits.insert(bit);
 
-                               if (cell->type == RTLIL::escape_id(toutpad_celltype) && cell->hasPort(RTLIL::escape_id(toutpad_portname3)))
-                                       for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(toutpad_portname3))))
-                                               skip_wire_bits.insert(bit);
-
-                               if (cell->type == RTLIL::escape_id(tinoutpad_celltype) && cell->hasPort(RTLIL::escape_id(tinoutpad_portname4)))
-                                       for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(tinoutpad_portname4))))
-                                               skip_wire_bits.insert(bit);
-                       }
-
                        if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty())
                        {
                                dict<SigBit, pair<IdString, pool<IdString>>> tbuf_bits;
index 05e46b4e70d12e5d4dd7bd2562c0b5a60e076a2a..d5815ca771b2bf3c7e220c96b9e0f988e53cbafc 100644 (file)
@@ -42,10 +42,12 @@ module OBUF(output O, input I);
   assign O = I;
 endmodule
 
+(* clkbuf_driver = "O" *)
 module BUFG(output O, input I);
   assign O = I;
 endmodule
 
+(* clkbuf_driver = "O" *)
 module BUFGCTRL(
     output O,
     input I0, input I1,
@@ -72,6 +74,7 @@ assign O = S0_true ? I0_internal : (S1_true ? I1_internal : INIT_OUT);
 
 endmodule
 
+(* clkbuf_driver = "O" *)
 module BUFHCE(output O, input I, input CE);
 
 parameter [0:0] INIT_OUT = 1'b0;
@@ -213,6 +216,7 @@ endmodule
 
 `endif
 
+(* clkbuf_sink = "C" *)
 module FDRE (output reg Q, input C, CE, D, R);
   parameter [0:0] INIT = 1'b0;
   parameter [0:0] IS_C_INVERTED = 1'b0;
@@ -225,6 +229,7 @@ module FDRE (output reg Q, input C, CE, D, R);
   endcase endgenerate
 endmodule
 
+(* clkbuf_sink = "C" *)
 module FDSE (output reg Q, input C, CE, D, S);
   parameter [0:0] INIT = 1'b1;
   parameter [0:0] IS_C_INVERTED = 1'b0;
@@ -237,6 +242,7 @@ module FDSE (output reg Q, input C, CE, D, S);
   endcase endgenerate
 endmodule
 
+(* clkbuf_sink = "C" *)
 module FDCE (output reg Q, input C, CE, D, CLR);
   parameter [0:0] INIT = 1'b0;
   parameter [0:0] IS_C_INVERTED = 1'b0;
@@ -251,6 +257,7 @@ module FDCE (output reg Q, input C, CE, D, CLR);
   endcase endgenerate
 endmodule
 
+(* clkbuf_sink = "C" *)
 module FDPE (output reg Q, input C, CE, D, PRE);
   parameter [0:0] INIT = 1'b1;
   parameter [0:0] IS_C_INVERTED = 1'b0;
@@ -265,30 +272,35 @@ module FDPE (output reg Q, input C, CE, D, PRE);
   endcase endgenerate
 endmodule
 
+(* clkbuf_sink = "C" *)
 module FDRE_1 (output reg Q, input C, CE, D, R);
   parameter [0:0] INIT = 1'b0;
   initial Q <= INIT;
   always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D;
 endmodule
 
+(* clkbuf_sink = "C" *)
 module FDSE_1 (output reg Q, input C, CE, D, S);
   parameter [0:0] INIT = 1'b1;
   initial Q <= INIT;
   always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D;
 endmodule
 
+(* clkbuf_sink = "C" *)
 module FDCE_1 (output reg Q, input C, CE, D, CLR);
   parameter [0:0] INIT = 1'b0;
   initial Q <= INIT;
   always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
 endmodule
 
+(* clkbuf_sink = "C" *)
 module FDPE_1 (output reg Q, input C, CE, D, PRE);
   parameter [0:0] INIT = 1'b1;
   initial Q <= INIT;
   always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
 endmodule
 
+(* clkbuf_sink = "WCLK" *)
 (* abc_box_id = 5, abc_scc_break="D,WE" *)
 module RAM32X1D (
   output DPO, SPO,
@@ -307,6 +319,7 @@ module RAM32X1D (
   always @(posedge clk) if (WE) mem[a] <= D;
 endmodule
 
+(* clkbuf_sink = "WCLK" *)
 (* abc_box_id = 6, abc_scc_break="D,WE" *)
 module RAM64X1D (
   output DPO, SPO,
@@ -325,6 +338,7 @@ module RAM64X1D (
   always @(posedge clk) if (WE) mem[a] <= D;
 endmodule
 
+(* clkbuf_sink = "WCLK" *)
 (* abc_box_id = 7, abc_scc_break="D,WE" *)
 module RAM128X1D (
   output       DPO, SPO,
@@ -340,6 +354,7 @@ module RAM128X1D (
   always @(posedge clk) if (WE) mem[A] <= D;
 endmodule
 
+(* clkbuf_sink = "CLK" *)
 module SRL16E (
   output Q,
   input A0, A1, A2, A3, CE, CLK, D
@@ -358,6 +373,7 @@ module SRL16E (
   endgenerate
 endmodule
 
+(* clkbuf_sink = "CLK" *)
 module SRLC32E (
   output Q,
   output Q31,
index 53b52882097f53724d9aa5a38f1257a8519d3fed..3291e46a8877bf6d2809dd5582bfc7240c268141 100644 (file)
@@ -1,7 +1,12 @@
 #!/bin/bash
 
 set -e
-libdir="/opt/Xilinx/Vivado/2018.1/data/verilog/src"
+if [ -z "$1" ]
+then
+       libdir="/opt/Xilinx/Vivado/2018.1/data/verilog/src"
+else
+       libdir=$1
+fi
 
 function xtract_cell_decl()
 {
@@ -24,33 +29,33 @@ function xtract_cell_decl()
        echo
 
        # Design elements types listed in Xilinx UG953
-       xtract_cell_decl BSCANE2
-       # xtract_cell_decl BUFG
-       xtract_cell_decl BUFGCE
-       xtract_cell_decl BUFGCE_1
-       #xtract_cell_decl BUFGCTRL
-       xtract_cell_decl BUFGMUX
-       xtract_cell_decl BUFGMUX_1
-       xtract_cell_decl BUFGMUX_CTRL
-       xtract_cell_decl BUFH
-       #xtract_cell_decl BUFHCE
-       xtract_cell_decl BUFIO
-       xtract_cell_decl BUFMR
-       xtract_cell_decl BUFMRCE
-       xtract_cell_decl BUFR
+       xtract_cell_decl BSCANE2 "(* keep *)"
+       # xtract_cell_decl BUFG "(* clkbuf_driver = \"O\" *)"
+       xtract_cell_decl BUFGCE "(* clkbuf_driver = \"O\" *)"
+       xtract_cell_decl BUFGCE_1 "(* clkbuf_driver = \"O\" *)"
+       #xtract_cell_decl BUFGCTRL "(* clkbuf_driver = \"O\" *)"
+       xtract_cell_decl BUFGMUX "(* clkbuf_driver = \"O\" *)"
+       xtract_cell_decl BUFGMUX_1 "(* clkbuf_driver = \"O\" *)"
+       xtract_cell_decl BUFGMUX_CTRL "(* clkbuf_driver = \"O\" *)"
+       xtract_cell_decl BUFH "(* clkbuf_driver = \"O\" *)"
+       #xtract_cell_decl BUFHCE "(* clkbuf_driver = \"O\" *)"
+       xtract_cell_decl BUFIO "(* clkbuf_driver = \"O\" *)"
+       xtract_cell_decl BUFMR "(* clkbuf_driver = \"O\" *)"
+       xtract_cell_decl BUFMRCE "(* clkbuf_driver = \"O\" *)"
+       xtract_cell_decl BUFR "(* clkbuf_driver = \"O\" *)"
        xtract_cell_decl CAPTUREE2 "(* keep *)"
        # xtract_cell_decl CARRY4
-       xtract_cell_decl CFGLUT5
+       xtract_cell_decl CFGLUT5 "(* clkbuf_sink = \"CLK\" *)"
        xtract_cell_decl DCIRESET "(* keep *)"
        xtract_cell_decl DNA_PORT
-       xtract_cell_decl DSP48E1
+       xtract_cell_decl DSP48E1 "(* clkbuf_sink = \"CLK\" *)"
        xtract_cell_decl EFUSE_USR
        # xtract_cell_decl FDCE
        # xtract_cell_decl FDPE
        # xtract_cell_decl FDRE
        # xtract_cell_decl FDSE
-       xtract_cell_decl FIFO18E1
-       xtract_cell_decl FIFO36E1
+       xtract_cell_decl FIFO18E1 "(* clkbuf_sink = \"RDCLK,WRCLK\" *)"
+       xtract_cell_decl FIFO36E1 "(* clkbuf_sink = \"RDCLK,WRCLK\" *)"
        xtract_cell_decl FRAME_ECCE2
        xtract_cell_decl GTHE2_CHANNEL
        xtract_cell_decl GTHE2_COMMON
@@ -58,31 +63,34 @@ function xtract_cell_decl()
        xtract_cell_decl GTPE2_COMMON
        xtract_cell_decl GTXE2_CHANNEL
        xtract_cell_decl GTXE2_COMMON
-       # xtract_cell_decl IBUF
-       xtract_cell_decl IBUF_IBUFDISABLE
-       xtract_cell_decl IBUF_INTERMDISABLE
-       xtract_cell_decl IBUFDS
-       xtract_cell_decl IBUFDS_DIFF_OUT
-       xtract_cell_decl IBUFDS_DIFF_OUT_IBUFDISABLE
-       xtract_cell_decl IBUFDS_DIFF_OUT_INTERMDISABLE
-       xtract_cell_decl IBUFDS_GTE2
-       xtract_cell_decl IBUFDS_IBUFDISABLE
-       xtract_cell_decl IBUFDS_INTERMDISABLE
+       # xtract_cell_decl IBUF "(* iopad_external_pin = \"I\" *)"
+       xtract_cell_decl IBUF_IBUFDISABLE "(* iopad_external_pin = \"I\" *)"
+       xtract_cell_decl IBUF_INTERMDISABLE "(* iopad_external_pin = \"I\" *)"
+       xtract_cell_decl IBUFDS "(* iopad_external_pin = \"I,IB\" *)"
+       xtract_cell_decl IBUFDS_DIFF_OUT "(* iopad_external_pin = \"I,IB\" *)"
+       xtract_cell_decl IBUFDS_DIFF_OUT_IBUFDISABLE "(* iopad_external_pin = \"I,IB\" *)"
+       xtract_cell_decl IBUFDS_DIFF_OUT_INTERMDISABLE "(* iopad_external_pin = \"I,IB\" *)"
+       xtract_cell_decl IBUFDS_GTE2 "(* iopad_external_pin = \"I,IB\" *)"
+       xtract_cell_decl IBUFDS_IBUFDISABLE "(* iopad_external_pin = \"I,IB\" *)"
+       xtract_cell_decl IBUFDS_INTERMDISABLE "(* iopad_external_pin = \"I,IB\" *)"
+       xtract_cell_decl IBUFG "(* iopad_external_pin = \"I\" *)"
+       xtract_cell_decl IBUFGDS "(* iopad_external_pin = \"I,IB\" *)"
+       xtract_cell_decl IBUFGDS_DIFF_OUT "(* iopad_external_pin = \"I,IB\" *)"
        xtract_cell_decl ICAPE2 "(* keep *)"
-       xtract_cell_decl IDDR
-       xtract_cell_decl IDDR_2CLK
-       xtract_cell_decl IDELAYCTRL "(* keep *)"
-       xtract_cell_decl IDELAYE2
-       xtract_cell_decl IN_FIFO
-       xtract_cell_decl IOBUF
-       xtract_cell_decl IOBUF_DCIEN
-       xtract_cell_decl IOBUF_INTERMDISABLE
-       xtract_cell_decl IOBUFDS
-       xtract_cell_decl IOBUFDS_DCIEN
-       xtract_cell_decl IOBUFDS_DIFF_OUT
-       xtract_cell_decl IOBUFDS_DIFF_OUT_DCIEN
-       xtract_cell_decl IOBUFDS_DIFF_OUT_INTERMDISABLE
-       xtract_cell_decl ISERDESE2
+       xtract_cell_decl IDDR "(* clkbuf_sink = \"C\" *)"
+       xtract_cell_decl IDDR_2CLK "(* clkbuf_sink = \"C,CB\" *)"
+       xtract_cell_decl IDELAYCTRL "(* keep *) (* clkbuf_sink = \"REFCLK\" *)"
+       xtract_cell_decl IDELAYE2 "(* clkbuf_sink = \"C\" *)"
+       xtract_cell_decl IN_FIFO "(* clkbuf_sink = \"RDCLK,WRCLK\" *)"
+       xtract_cell_decl IOBUF "(* iopad_external_pin = \"IO\" *)"
+       xtract_cell_decl IOBUF_DCIEN "(* iopad_external_pin = \"IO\" *)"
+       xtract_cell_decl IOBUF_INTERMDISABLE "(* iopad_external_pin = \"IO\" *)"
+       xtract_cell_decl IOBUFDS "(* iopad_external_pin = \"IO\" *)"
+       xtract_cell_decl IOBUFDS_DCIEN "(* iopad_external_pin = \"IO,IOB\" *)"
+       xtract_cell_decl IOBUFDS_DIFF_OUT "(* iopad_external_pin = \"IO,IOB\" *)"
+       xtract_cell_decl IOBUFDS_DIFF_OUT_DCIEN "(* iopad_external_pin = \"IO,IOB\" *)"
+       xtract_cell_decl IOBUFDS_DIFF_OUT_INTERMDISABLE "(* iopad_external_pin = \"IO,IOB\" *)"
+       xtract_cell_decl ISERDESE2 "(* clkbuf_sink = \"CLK,CLKB,CLKDIV,CLKDIVP,OCLK,OCLKB\" *)"
        xtract_cell_decl KEEPER
        xtract_cell_decl LDCE
        xtract_cell_decl LDPE
@@ -97,14 +105,14 @@ function xtract_cell_decl()
        xtract_cell_decl MMCME2_BASE
        # xtract_cell_decl MUXF7
        # xtract_cell_decl MUXF8
-       # xtract_cell_decl OBUF
-       xtract_cell_decl OBUFDS
-       xtract_cell_decl OBUFT
-       xtract_cell_decl OBUFTDS
-       xtract_cell_decl ODDR
-       xtract_cell_decl ODELAYE2
-       xtract_cell_decl OSERDESE2
-       xtract_cell_decl OUT_FIFO
+       # xtract_cell_decl OBUF "(* iopad_external_pin = \"O\" *)"
+       xtract_cell_decl OBUFDS "(* iopad_external_pin = \"O,OB\" *)"
+       xtract_cell_decl OBUFT "(* iopad_external_pin = \"O\" *)"
+       xtract_cell_decl OBUFTDS "(* iopad_external_pin = \"O,OB\" *)"
+       xtract_cell_decl ODDR "(* clkbuf_sink = \"C\" *)"
+       xtract_cell_decl ODELAYE2 "(* clkbuf_sink = \"C\" *)"
+       xtract_cell_decl OSERDESE2 "(* clkbuf_sink = \"CLK,CLKDIV\" *)"
+       xtract_cell_decl OUT_FIFO "(* clkbuf_sink = \"RDCLK,WRCLK\" *)"
        xtract_cell_decl PHASER_IN
        xtract_cell_decl PHASER_IN_PHY
        xtract_cell_decl PHASER_OUT
@@ -116,27 +124,27 @@ function xtract_cell_decl()
        xtract_cell_decl PS7 "(* keep *)"
        xtract_cell_decl PULLDOWN
        xtract_cell_decl PULLUP
-       #xtract_cell_decl RAM128X1D
-       xtract_cell_decl RAM128X1S
-       xtract_cell_decl RAM256X1S
-       xtract_cell_decl RAM32M
-       #xtract_cell_decl RAM32X1D
-       xtract_cell_decl RAM32X1S
-       xtract_cell_decl RAM32X1S_1
-       xtract_cell_decl RAM32X2S
-       xtract_cell_decl RAM64M
-       #xtract_cell_decl RAM64X1D
-       xtract_cell_decl RAM64X1S
-       xtract_cell_decl RAM64X1S_1
-       xtract_cell_decl RAM64X2S
-       # xtract_cell_decl RAMB18E1
-       # xtract_cell_decl RAMB36E1
+       #xtract_cell_decl RAM128X1D "(* clkbuf_sink = \"WCLK\" *)"
+       xtract_cell_decl RAM128X1S "(* clkbuf_sink = \"WCLK\" *)"
+       xtract_cell_decl RAM256X1S "(* clkbuf_sink = \"WCLK\" *)"
+       xtract_cell_decl RAM32M "(* clkbuf_sink = \"WCLK\" *)"
+       #xtract_cell_decl RAM32X1D "(* clkbuf_sink = \"WCLK\" *)"
+       xtract_cell_decl RAM32X1S "(* clkbuf_sink = \"WCLK\" *)"
+       xtract_cell_decl RAM32X1S_1 "(* clkbuf_sink = \"WCLK\" *)"
+       xtract_cell_decl RAM32X2S "(* clkbuf_sink = \"WCLK\" *)"
+       xtract_cell_decl RAM64M "(* clkbuf_sink = \"WCLK\" *)"
+       #xtract_cell_decl RAM64X1D "(* clkbuf_sink = \"WCLK\" *)"
+       xtract_cell_decl RAM64X1S "(* clkbuf_sink = \"WCLK\" *)"
+       xtract_cell_decl RAM64X1S_1 "(* clkbuf_sink = \"WCLK\" *)"
+       xtract_cell_decl RAM64X2S "(* clkbuf_sink = \"WCLK\" *)"
+       # xtract_cell_decl RAMB18E1 "(* clkbuf_sink = \"CLKARDCLK,CLKBWRCLK\" *)"
+       # xtract_cell_decl RAMB36E1 "(* clkbuf_sink = \"CLKARDCLK,CLKBWRCLK\" *)"
        xtract_cell_decl ROM128X1
        xtract_cell_decl ROM256X1
        xtract_cell_decl ROM32X1
        xtract_cell_decl ROM64X1
-       #xtract_cell_decl SRL16E
-       #xtract_cell_decl SRLC32E
+       #xtract_cell_decl SRL16E "(* clkbuf_sink = \"CLK\" *)"
+       #xtract_cell_decl SRLC32E "(* clkbuf_sink = \"CLK\" *)"
        xtract_cell_decl STARTUPE2 "(* keep *)"
        xtract_cell_decl USR_ACCESSE2
        xtract_cell_decl XADC
index 15fa1b63a499e24f2faba03206844f7fb9d1ba59..0fbbc0fdfff812432258c656dde5bbfca644f31b 100644 (file)
@@ -1,5 +1,6 @@
 // Created by cells_xtra.sh from Xilinx models
 
+(* keep *)
 module BSCANE2 (...);
     parameter DISABLE_JTAG = "FALSE";
     parameter integer JTAG_CHAIN = 1;
@@ -16,6 +17,7 @@ module BSCANE2 (...);
     input TDO;
 endmodule
 
+(* clkbuf_driver = "O" *)
 module BUFGCE (...);
     parameter CE_TYPE = "SYNC";
     parameter [0:0] IS_CE_INVERTED = 1'b0;
@@ -25,23 +27,28 @@ module BUFGCE (...);
     input I;
 endmodule
 
+(* clkbuf_driver = "O" *)
 module BUFGCE_1 (...);
     output O;
-    input CE, I;
+    input CE;
+    input I;
 endmodule
 
+(* clkbuf_driver = "O" *)
 module BUFGMUX (...);
     parameter CLK_SEL_TYPE = "SYNC";
     output O;
     input I0, I1, S;
 endmodule
 
+(* clkbuf_driver = "O" *)
 module BUFGMUX_1 (...);
     parameter CLK_SEL_TYPE = "SYNC";
     output O;
     input I0, I1, S;
 endmodule
 
+(* clkbuf_driver = "O" *)
 module BUFGMUX_CTRL (...);
     output O;
     input I0;
@@ -49,21 +56,25 @@ module BUFGMUX_CTRL (...);
     input S;
 endmodule
 
+(* clkbuf_driver = "O" *)
 module BUFH (...);
     output O;
     input I;
 endmodule
 
+(* clkbuf_driver = "O" *)
 module BUFIO (...);
     output O;
     input I;
 endmodule
 
+(* clkbuf_driver = "O" *)
 module BUFMR (...);
     output O;
     input I;
 endmodule
 
+(* clkbuf_driver = "O" *)
 module BUFMRCE (...);
     parameter CE_TYPE = "SYNC";
     parameter integer INIT_OUT = 0;
@@ -73,6 +84,7 @@ module BUFMRCE (...);
     input I;
 endmodule
 
+(* clkbuf_driver = "O" *)
 module BUFR (...);
     output O;
     input CE;
@@ -89,6 +101,7 @@ module CAPTUREE2 (...);
     input CLK;
 endmodule
 
+(* clkbuf_sink = "CLK" *)
 module CFGLUT5 (...);
     parameter [31:0] INIT = 32'h00000000;
     parameter [0:0] IS_CLK_INVERTED = 1'b0;
@@ -111,6 +124,7 @@ module DNA_PORT (...);
     input CLK, DIN, READ, SHIFT;
 endmodule
 
+(* clkbuf_sink = "CLK" *)
 module DSP48E1 (...);
     parameter integer ACASCREG = 1;
     parameter integer ADREG = 1;
@@ -198,6 +212,7 @@ module EFUSE_USR (...);
     output [31:0] EFUSEUSR;
 endmodule
 
+(* clkbuf_sink = "RDCLK,WRCLK" *)
 module FIFO18E1 (...);
     parameter ALMOST_EMPTY_OFFSET = 13'h0080;
     parameter ALMOST_FULL_OFFSET = 13'h0080;
@@ -236,6 +251,7 @@ module FIFO18E1 (...);
     input WREN;
 endmodule
 
+(* clkbuf_sink = "RDCLK,WRCLK" *)
 module FIFO36E1 (...);
     parameter ALMOST_EMPTY_OFFSET = 13'h0080;
     parameter ALMOST_FULL_OFFSET = 13'h0080;
@@ -1963,6 +1979,7 @@ module GTXE2_COMMON (...);
     input [7:0] PMARSVD;
 endmodule
 
+(* iopad_external_pin = "I" *)
 module IBUF_IBUFDISABLE (...);
     parameter IBUF_LOW_PWR = "TRUE";
     parameter IOSTANDARD = "DEFAULT";
@@ -1973,6 +1990,7 @@ module IBUF_IBUFDISABLE (...);
     input IBUFDISABLE;
 endmodule
 
+(* iopad_external_pin = "I" *)
 module IBUF_INTERMDISABLE (...);
     parameter IBUF_LOW_PWR = "TRUE";
     parameter IOSTANDARD = "DEFAULT";
@@ -1984,6 +2002,7 @@ module IBUF_INTERMDISABLE (...);
     input INTERMDISABLE;
 endmodule
 
+(* iopad_external_pin = "I,IB" *)
 module IBUFDS (...);
     parameter CAPACITANCE = "DONT_CARE";
     parameter DIFF_TERM = "FALSE";
@@ -1996,6 +2015,7 @@ module IBUFDS (...);
     input I, IB;
 endmodule
 
+(* iopad_external_pin = "I,IB" *)
 module IBUFDS_DIFF_OUT (...);
     parameter DIFF_TERM = "FALSE";
     parameter DQS_BIAS = "FALSE";
@@ -2005,6 +2025,7 @@ module IBUFDS_DIFF_OUT (...);
     input I, IB;
 endmodule
 
+(* iopad_external_pin = "I,IB" *)
 module IBUFDS_DIFF_OUT_IBUFDISABLE (...);
     parameter DIFF_TERM = "FALSE";
     parameter DQS_BIAS = "FALSE";
@@ -2019,6 +2040,7 @@ module IBUFDS_DIFF_OUT_IBUFDISABLE (...);
     input IBUFDISABLE;
 endmodule
 
+(* iopad_external_pin = "I,IB" *)
 module IBUFDS_DIFF_OUT_INTERMDISABLE (...);
     parameter DIFF_TERM = "FALSE";
     parameter DQS_BIAS = "FALSE";
@@ -2034,6 +2056,7 @@ module IBUFDS_DIFF_OUT_INTERMDISABLE (...);
     input INTERMDISABLE;
 endmodule
 
+(* iopad_external_pin = "I,IB" *)
 module IBUFDS_GTE2 (...);
     parameter CLKCM_CFG = "TRUE";
     parameter CLKRCV_TRST = "TRUE";
@@ -2045,6 +2068,7 @@ module IBUFDS_GTE2 (...);
     input IB;
 endmodule
 
+(* iopad_external_pin = "I,IB" *)
 module IBUFDS_IBUFDISABLE (...);
     parameter DIFF_TERM = "FALSE";
     parameter DQS_BIAS = "FALSE";
@@ -2058,6 +2082,7 @@ module IBUFDS_IBUFDISABLE (...);
     input IBUFDISABLE;
 endmodule
 
+(* iopad_external_pin = "I,IB" *)
 module IBUFDS_INTERMDISABLE (...);
     parameter DIFF_TERM = "FALSE";
     parameter DQS_BIAS = "FALSE";
@@ -2072,6 +2097,37 @@ module IBUFDS_INTERMDISABLE (...);
     input INTERMDISABLE;
 endmodule
 
+(* iopad_external_pin = "I" *)
+module IBUFG (...);
+    parameter CAPACITANCE = "DONT_CARE";
+    parameter IBUF_DELAY_VALUE = "0";
+    parameter IBUF_LOW_PWR = "TRUE";
+    parameter IOSTANDARD = "DEFAULT";
+    output O;
+    input I;
+endmodule
+
+(* iopad_external_pin = "I,IB" *)
+module IBUFGDS (...);
+    parameter CAPACITANCE = "DONT_CARE";
+    parameter DIFF_TERM = "FALSE";
+    parameter IBUF_DELAY_VALUE = "0";
+    parameter IBUF_LOW_PWR = "TRUE";
+    parameter IOSTANDARD = "DEFAULT";
+    output O;
+    input I, IB;
+endmodule
+
+(* iopad_external_pin = "I,IB" *)
+module IBUFGDS_DIFF_OUT (...);
+    parameter DIFF_TERM = "FALSE";
+    parameter DQS_BIAS = "FALSE";
+    parameter IBUF_LOW_PWR = "TRUE";
+    parameter IOSTANDARD = "DEFAULT";
+    output O, OB;
+    input I, IB;
+endmodule
+
 (* keep *)
 module ICAPE2 (...);
     parameter [31:0] DEVICE_ID = 32'h04244093;
@@ -2084,6 +2140,7 @@ module ICAPE2 (...);
     input [31:0] I;
 endmodule
 
+(* clkbuf_sink = "C" *)
 module IDDR (...);
     parameter DDR_CLK_EDGE = "OPPOSITE_EDGE";
     parameter INIT_Q1 = 1'b0;
@@ -2102,6 +2159,7 @@ module IDDR (...);
     input S;
 endmodule
 
+(* clkbuf_sink = "C,CB" *)
 module IDDR_2CLK (...);
     parameter DDR_CLK_EDGE = "OPPOSITE_EDGE";
     parameter INIT_Q1 = 1'b0;
@@ -2120,7 +2178,7 @@ module IDDR_2CLK (...);
     input S;
 endmodule
 
-(* keep *)
+(* keep *) (* clkbuf_sink = "REFCLK" *)
 module IDELAYCTRL (...);
     parameter SIM_DEVICE = "7SERIES";
     output RDY;
@@ -2128,6 +2186,7 @@ module IDELAYCTRL (...);
     input RST;
 endmodule
 
+(* clkbuf_sink = "C" *)
 module IDELAYE2 (...);
     parameter CINVCTRL_SEL = "FALSE";
     parameter DELAY_SRC = "IDATAIN";
@@ -2155,6 +2214,7 @@ module IDELAYE2 (...);
     input REGRST;
 endmodule
 
+(* clkbuf_sink = "RDCLK,WRCLK" *)
 module IN_FIFO (...);
     parameter integer ALMOST_EMPTY_VALUE = 1;
     parameter integer ALMOST_FULL_VALUE = 1;
@@ -2191,6 +2251,7 @@ module IN_FIFO (...);
     input [7:0] D6;
 endmodule
 
+(* iopad_external_pin = "IO" *)
 module IOBUF (...);
     parameter integer DRIVE = 12;
     parameter IBUF_LOW_PWR = "TRUE";
@@ -2201,6 +2262,7 @@ module IOBUF (...);
     input I, T;
 endmodule
 
+(* iopad_external_pin = "IO" *)
 module IOBUF_DCIEN (...);
     parameter integer DRIVE = 12;
     parameter IBUF_LOW_PWR = "TRUE";
@@ -2216,6 +2278,7 @@ module IOBUF_DCIEN (...);
     input T;
 endmodule
 
+(* iopad_external_pin = "IO" *)
 module IOBUF_INTERMDISABLE (...);
     parameter integer DRIVE = 12;
     parameter IBUF_LOW_PWR = "TRUE";
@@ -2231,6 +2294,7 @@ module IOBUF_INTERMDISABLE (...);
     input T;
 endmodule
 
+(* iopad_external_pin = "IO" *)
 module IOBUFDS (...);
     parameter DIFF_TERM = "FALSE";
     parameter DQS_BIAS = "FALSE";
@@ -2242,6 +2306,7 @@ module IOBUFDS (...);
     input I, T;
 endmodule
 
+(* iopad_external_pin = "IO,IOB" *)
 module IOBUFDS_DCIEN (...);
     parameter DIFF_TERM = "FALSE";
     parameter DQS_BIAS = "FALSE";
@@ -2259,6 +2324,7 @@ module IOBUFDS_DCIEN (...);
     input T;
 endmodule
 
+(* iopad_external_pin = "IO,IOB" *)
 module IOBUFDS_DIFF_OUT (...);
     parameter DIFF_TERM = "FALSE";
     parameter DQS_BIAS = "FALSE";
@@ -2273,6 +2339,7 @@ module IOBUFDS_DIFF_OUT (...);
     input TS;
 endmodule
 
+(* iopad_external_pin = "IO,IOB" *)
 module IOBUFDS_DIFF_OUT_DCIEN (...);
     parameter DIFF_TERM = "FALSE";
     parameter DQS_BIAS = "FALSE";
@@ -2291,6 +2358,7 @@ module IOBUFDS_DIFF_OUT_DCIEN (...);
     input TS;
 endmodule
 
+(* iopad_external_pin = "IO,IOB" *)
 module IOBUFDS_DIFF_OUT_INTERMDISABLE (...);
     parameter DIFF_TERM = "FALSE";
     parameter DQS_BIAS = "FALSE";
@@ -2309,6 +2377,7 @@ module IOBUFDS_DIFF_OUT_INTERMDISABLE (...);
     input TS;
 endmodule
 
+(* clkbuf_sink = "CLK,CLKB,CLKDIV,CLKDIVP,OCLK,OCLKB" *)
 module ISERDESE2 (...);
     parameter DATA_RATE = "DDR";
     parameter integer DATA_WIDTH = 4;
@@ -2529,6 +2598,7 @@ module MMCME2_BASE (...);
     input RST;
 endmodule
 
+(* iopad_external_pin = "O,OB" *)
 module OBUFDS (...);
     parameter CAPACITANCE = "DONT_CARE";
     parameter IOSTANDARD = "DEFAULT";
@@ -2537,6 +2607,7 @@ module OBUFDS (...);
     input I;
 endmodule
 
+(* iopad_external_pin = "O" *)
 module OBUFT (...);
     parameter CAPACITANCE = "DONT_CARE";
     parameter integer DRIVE = 12;
@@ -2546,6 +2617,7 @@ module OBUFT (...);
     input I, T;
 endmodule
 
+(* iopad_external_pin = "O,OB" *)
 module OBUFTDS (...);
     parameter CAPACITANCE = "DONT_CARE";
     parameter IOSTANDARD = "DEFAULT";
@@ -2554,6 +2626,7 @@ module OBUFTDS (...);
     input I, T;
 endmodule
 
+(* clkbuf_sink = "C" *)
 module ODDR (...);
     output Q;
     input C;
@@ -2572,6 +2645,7 @@ module ODDR (...);
     parameter XON = "TRUE";
 endmodule
 
+(* clkbuf_sink = "C" *)
 module ODELAYE2 (...);
     parameter CINVCTRL_SEL = "FALSE";
     parameter DELAY_SRC = "ODATAIN";
@@ -2598,6 +2672,7 @@ module ODELAYE2 (...);
     input REGRST;
 endmodule
 
+(* clkbuf_sink = "CLK,CLKDIV" *)
 module OSERDESE2 (...);
     parameter DATA_RATE_OQ = "DDR";
     parameter DATA_RATE_TQ = "DDR";
@@ -2653,6 +2728,7 @@ module OSERDESE2 (...);
     input TCE;
 endmodule
 
+(* clkbuf_sink = "RDCLK,WRCLK" *)
 module OUT_FIFO (...);
     parameter integer ALMOST_EMPTY_VALUE = 1;
     parameter integer ALMOST_FULL_VALUE = 1;
@@ -3655,6 +3731,7 @@ module PULLUP (...);
     output O;
 endmodule
 
+(* clkbuf_sink = "WCLK" *)
 module RAM128X1S (...);
     parameter [127:0] INIT = 128'h00000000000000000000000000000000;
     parameter [0:0] IS_WCLK_INVERTED = 1'b0;
@@ -3662,6 +3739,7 @@ module RAM128X1S (...);
     input A0, A1, A2, A3, A4, A5, A6, D, WCLK, WE;
 endmodule
 
+(* clkbuf_sink = "WCLK" *)
 module RAM256X1S (...);
     parameter [255:0] INIT = 256'h0;
     parameter [0:0] IS_WCLK_INVERTED = 1'b0;
@@ -3672,6 +3750,7 @@ module RAM256X1S (...);
     input WE;
 endmodule
 
+(* clkbuf_sink = "WCLK" *)
 module RAM32M (...);
     parameter [63:0] INIT_A = 64'h0000000000000000;
     parameter [63:0] INIT_B = 64'h0000000000000000;
@@ -3694,6 +3773,7 @@ module RAM32M (...);
     input WE;
 endmodule
 
+(* clkbuf_sink = "WCLK" *)
 module RAM32X1S (...);
     parameter [31:0] INIT = 32'h00000000;
     parameter [0:0] IS_WCLK_INVERTED = 1'b0;
@@ -3701,6 +3781,7 @@ module RAM32X1S (...);
     input A0, A1, A2, A3, A4, D, WCLK, WE;
 endmodule
 
+(* clkbuf_sink = "WCLK" *)
 module RAM32X1S_1 (...);
     parameter [31:0] INIT = 32'h00000000;
     parameter [0:0] IS_WCLK_INVERTED = 1'b0;
@@ -3708,6 +3789,7 @@ module RAM32X1S_1 (...);
     input A0, A1, A2, A3, A4, D, WCLK, WE;
 endmodule
 
+(* clkbuf_sink = "WCLK" *)
 module RAM32X2S (...);
     parameter [31:0] INIT_00 = 32'h00000000;
     parameter [31:0] INIT_01 = 32'h00000000;
@@ -3716,6 +3798,7 @@ module RAM32X2S (...);
     input A0, A1, A2, A3, A4, D0, D1, WCLK, WE;
 endmodule
 
+(* clkbuf_sink = "WCLK" *)
 module RAM64M (...);
     parameter [63:0] INIT_A = 64'h0000000000000000;
     parameter [63:0] INIT_B = 64'h0000000000000000;
@@ -3738,6 +3821,7 @@ module RAM64M (...);
     input WE;
 endmodule
 
+(* clkbuf_sink = "WCLK" *)
 module RAM64X1S (...);
     parameter [63:0] INIT = 64'h0000000000000000;
     parameter [0:0] IS_WCLK_INVERTED = 1'b0;
@@ -3745,6 +3829,7 @@ module RAM64X1S (...);
     input A0, A1, A2, A3, A4, A5, D, WCLK, WE;
 endmodule
 
+(* clkbuf_sink = "WCLK" *)
 module RAM64X1S_1 (...);
     parameter [63:0] INIT = 64'h0000000000000000;
     parameter [0:0] IS_WCLK_INVERTED = 1'b0;
@@ -3752,6 +3837,7 @@ module RAM64X1S_1 (...);
     input A0, A1, A2, A3, A4, A5, D, WCLK, WE;
 endmodule
 
+(* clkbuf_sink = "WCLK" *)
 module RAM64X2S (...);
     parameter [63:0] INIT_00 = 64'h0000000000000000;
     parameter [63:0] INIT_01 = 64'h0000000000000000;
index d143c68237c471e5c6a7968cbcb7661774a91844..a7362d26b6baf5175ebea47704649bd62a053e25 100644 (file)
@@ -63,6 +63,9 @@ struct SynthXilinxPass : public ScriptPass
                log("        generate an output netlist (and BLIF file) suitable for VPR\n");
                log("        (this feature is experimental and incomplete)\n");
                log("\n");
+               log("    -ise\n");
+               log("        generate an output netlist suitable for ISE\n");
+               log("\n");
                log("    -nobram\n");
                log("        disable inference of block rams\n");
                log("\n");
@@ -78,6 +81,12 @@ struct SynthXilinxPass : public ScriptPass
                log("    -nowidelut\n");
                log("        do not use MUXF[78] resources to implement LUTs larger than LUT6s\n");
                log("\n");
+               log("    -iopads\n");
+               log("        perform I/O buffer insertion (selected automatically by -ise)\n");
+               log("\n");
+               log("    -noiopads\n");
+               log("        disable I/O buffer insertion (only useful with -ise)\n");
+               log("\n");
                log("    -widemux <int>\n");
                log("        enable inference of hard multiplexer resources (MUXF[78]) for muxes at or\n");
                log("        above this number of inputs (minimum value 2, recommended value >= 5).\n");
@@ -104,7 +113,7 @@ struct SynthXilinxPass : public ScriptPass
        }
 
        std::string top_opt, edif_file, blif_file, family;
-       bool flatten, retime, vpr, nobram, nodram, nosrl, nocarry, nowidelut, abc9;
+       bool flatten, retime, vpr, ise, iopads, noiopads, nobram, nodram, nosrl, nocarry, nowidelut, abc9;
        int widemux;
 
        void clear_flags() YS_OVERRIDE
@@ -116,6 +125,9 @@ struct SynthXilinxPass : public ScriptPass
                flatten = false;
                retime = false;
                vpr = false;
+               ise = false;
+               iopads = false;
+               noiopads = false;
                nocarry = false;
                nobram = false;
                nodram = false;
@@ -178,6 +190,18 @@ struct SynthXilinxPass : public ScriptPass
                                vpr = true;
                                continue;
                        }
+                       if (args[argidx] == "-ise") {
+                               ise = true;
+                               continue;
+                       }
+                       if (args[argidx] == "-iopads") {
+                               iopads = true;
+                               continue;
+                       }
+                       if (args[argidx] == "-noiopads") {
+                               noiopads = true;
+                               continue;
+                       }
                        if (args[argidx] == "-nocarry") {
                                nocarry = true;
                                continue;
@@ -410,6 +434,17 @@ struct SynthXilinxPass : public ScriptPass
                        run("clean");
                }
 
+               if (check_label("finalize")) {
+                       bool do_iopads = iopads || (ise && !noiopads);
+                       if (help_mode || do_iopads)
+                               run("clkbufmap -buf BUFG O:I -inpad IBUFG O:I", "(-inpad passed if '-iopads' or '-ise' and not '-noiopads')");
+                       else
+                               run("clkbufmap -buf BUFG O:I");
+
+                       if (do_iopads)
+                               run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I A:top", "(only if '-iopads' or '-ise' and not '-noiopads')");
+               }
+
                if (check_label("check")) {
                        run("hierarchy -check");
                        run("stat -tech xilinx");
index eb1a2957984dde50d5ea4b5ff7d0a98fba79d358..1287e2c53b597e3cbd35511db467d36f4b3fd320 100644 (file)
@@ -1,3 +1,4 @@
+(* clkbuf_sink = "CLKAWRCLK,CLKBRDCLK" *)
 module RAMB8BWER (
        input CLKAWRCLK,
        input CLKBRDCLK,
@@ -86,6 +87,7 @@ module RAMB8BWER (
        parameter SIM_COLLISION_CHECK = "ALL";
 endmodule
 
+(* clkbuf_sink = "CLKA,CLKB" *)
 module RAMB16BWER (
        input CLKA,
        input CLKB,
index a682ba4a72926b7ae506673edcdd5874fa4a4bb6..046a8fa26d4d8fe2137b6faa245470d0fc05c817 100644 (file)
@@ -1,3 +1,4 @@
+(* clkbuf_sink = "CLKARDCLK,CLKBWRCLK" *)
 module RAMB18E1 (
        input CLKARDCLK,
        input CLKBWRCLK,
@@ -122,6 +123,7 @@ module RAMB18E1 (
        parameter SIM_DEVICE = "VIRTEX6";
 endmodule
 
+(* clkbuf_sink = "CLKARDCLK,CLKBWRCLK" *)
 module RAMB36E1 (
        input CLKARDCLK,
        input CLKBWRCLK,