From 70c607d7dde23b709ffd36c47680cddcc4666fcd Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 6 Sep 2019 13:28:15 -0700
Subject: [PATCH 1/4] Document (* gentb_skip *) attr for test_autotb

---
 passes/tests/test_autotb.cc | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc
index bfb1d6642..a5ac3130f 100644
--- a/passes/tests/test_autotb.cc
+++ b/passes/tests/test_autotb.cc
@@ -345,6 +345,9 @@ struct TestAutotbBackend : public Backend {
 		log("value after initialization. This can e.g. be used to force a reset signal\n");
 		log("low in order to explore more inner states in a state machine.\n");
 		log("\n");
+		log("The attribute 'gentb_skip' can be attached to modules to suppress testbench\n");
+		log("generation.\n");
+		log("\n");
 		log("    -n <int>\n");
 		log("        number of iterations the test bench should run (default = 1000)\n");
 		log("\n");

From c9f9518de4af34b2539d230c0894b04d174b755d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= <koriakin@0x04.net>
Date: Wed, 28 Aug 2019 14:58:14 +0000
Subject: [PATCH 2/4] Added extractinv pass

---
 CHANGELOG                    |   1 +
 README.md                    |   6 ++
 passes/techmap/Makefile.inc  |   1 +
 passes/techmap/extractinv.cc | 123 +++++++++++++++++++++++++++++++++++
 tests/techmap/extractinv.ys  |  41 ++++++++++++
 5 files changed, 172 insertions(+)
 create mode 100644 passes/techmap/extractinv.cc
 create mode 100644 tests/techmap/extractinv.ys

diff --git a/CHANGELOG b/CHANGELOG
index 890fad978..2e73d5895 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -27,6 +27,7 @@ Yosys 0.9 .. Yosys 0.9-dev
     - Improve attribute and parameter encoding in JSON to avoid ambiguities between
       bit vectors and strings containing [01xz]*
     - Added "clkbufmap" pass
+    - Added "extractinv" pass and "invertible_pin" attribute
     - Added "synth_xilinx -family xc6s" for Spartan 6 support (experimental)
     - Added "synth_xilinx -ise" (experimental)
     - Added "synth_xilinx -iopad"
diff --git a/README.md b/README.md
index af3333e1d..fdd4bb410 100644
--- a/README.md
+++ b/README.md
@@ -347,6 +347,12 @@ Verilog Attributes and non-standard features
   automatic clock buffer insertion by ``clkbufmap``. This behaviour can be
   overridden by providing a custom selection to ``clkbufmap``.
 
+- The ``invertible_pin`` attribute can be set on a port to mark it as
+  invertible via a cell parameter.  The name of the inversion parameter
+  is specified as the value of this attribute.  The value of the inversion
+  parameter must be of the same width as the port, with 1 indicating
+  an inverted bit and 0 indicating a non-inverted bit.
+
 - The ``iopad_external_pin`` attribute on a blackbox module's port marks
   it as the external-facing pin of an I/O pad, and prevents ``iopadmap``
   from inserting another pad cell on it.
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index 631a80aa5..cd357d72a 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -40,6 +40,7 @@ OBJS += passes/techmap/attrmap.o
 OBJS += passes/techmap/zinit.o
 OBJS += passes/techmap/dff2dffs.o
 OBJS += passes/techmap/flowmap.o
+OBJS += passes/techmap/extractinv.o
 endif
 
 GENFILES += passes/techmap/techmap.inc
diff --git a/passes/techmap/extractinv.cc b/passes/techmap/extractinv.cc
new file mode 100644
index 000000000..dda71f12a
--- /dev/null
+++ b/passes/techmap/extractinv.cc
@@ -0,0 +1,123 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2019  Marcin Koƛcielnicki <mwk@0x04.net>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+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);
+	}
+}
+
+struct ExtractinvPass : public Pass {
+	ExtractinvPass() : Pass("extractinv", "extract explicit inverter cells for invertible cell pins") { }
+	void help() YS_OVERRIDE
+	{
+		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+		log("\n");
+		log("    extractinv [options] [selection]\n");
+		log("\n");
+		log("Searches the design for all cells with invertible pins controlled by a cell\n");
+		log("parameter (eg. IS_CLK_INVERTED on many Xilinx cells) and removes the parameter.\n");
+		log("If the parameter was set to 1, inserts an explicit inverter cell in front of\n");
+		log("the pin instead.  Normally used for output to ISE, which does not support the\n");
+		log("inversion parameters.\n");
+		log("\n");
+		log("To mark a cell port as invertible, use (* invertible_pin = \"param_name\" *)\n");
+		log("on the wire in the blackbox module.  The parameter value should have\n");
+		log("the same width as the port, and will be effectively XORed with it.\n");
+		log("\n");
+		log("    -inv <celltype> <portname_out>:<portname_in>\n");
+		log("        Specifies the cell type to use for the inverters and its port names.\n");
+		log("        This option is required.\n");
+		log("\n");
+	}
+
+	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+	{
+		log_header(design, "Executing EXTRACTINV pass (extracting pin inverters).\n");
+
+		std::string inv_celltype, inv_portname, inv_portname2;
+
+		size_t argidx;
+		for (argidx = 1; argidx < args.size(); argidx++)
+		{
+			std::string arg = args[argidx];
+			if (arg == "-inv" && argidx+2 < args.size()) {
+				inv_celltype = args[++argidx];
+				inv_portname = args[++argidx];
+				split_portname_pair(inv_portname, inv_portname2);
+				continue;
+			}
+			break;
+		}
+		extra_args(args, argidx, design);
+
+		if (inv_celltype.empty())
+			log_error("The -inv option is required.\n");
+
+		for (auto module : design->selected_modules())
+		{
+			for (auto cell : module->selected_cells())
+			for (auto port : cell->connections()) {
+				auto cell_module = design->module(cell->type);
+				if (!cell_module)
+					continue;
+				auto cell_wire = cell_module->wire(port.first);
+				if (!cell_wire)
+					continue;
+				auto it = cell_wire->attributes.find("\\invertible_pin");
+				if (it == cell_wire->attributes.end())
+					continue;
+				IdString param_name = RTLIL::escape_id(it->second.decode_string());
+				auto it2 = cell->parameters.find(param_name);
+				// Inversion not used -- skip.
+				if (it2 == cell->parameters.end())
+					continue;
+				SigSpec sig = port.second;
+				if (it2->second.size() != sig.size())
+					log_error("The inversion parameter needs to be the same width as the port (%s.%s port %s parameter %s)", log_id(module->name), log_id(cell->type), log_id(port.first), log_id(param_name));
+				RTLIL::Const invmask = it2->second;
+				cell->parameters.erase(param_name);
+				if (invmask.is_fully_zero())
+					continue;
+				Wire *iwire = module->addWire(NEW_ID, sig.size());
+				for (int i = 0; i < sig.size(); i++)
+					if (invmask[i] == State::S1) {
+						RTLIL::Cell *icell = module->addCell(NEW_ID, RTLIL::escape_id(inv_celltype));
+						icell->setPort(RTLIL::escape_id(inv_portname), SigSpec(iwire, i));
+						icell->setPort(RTLIL::escape_id(inv_portname2), sig[i]);
+						log("Inserting %s on %s.%s.%s[%d].\n", inv_celltype.c_str(), log_id(module), log_id(cell->type), log_id(port.first), i);
+						sig[i] = SigBit(iwire, i);
+					}
+				cell->setPort(port.first, sig);
+			}
+		}
+	}
+} ExtractinvPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/tests/techmap/extractinv.ys b/tests/techmap/extractinv.ys
new file mode 100644
index 000000000..6146f829a
--- /dev/null
+++ b/tests/techmap/extractinv.ys
@@ -0,0 +1,41 @@
+read_verilog << EOT
+
+module ff4(...);
+parameter [0:0] CLK_INV = 1'b0;
+parameter [3:0] DATA_INV = 4'b0000;
+(* invertible_pin = "CLK_INV" *)
+input clk;
+(* invertible_pin = "DATA_INV" *)
+input [3:0] d;
+output [3:0] q;
+endmodule
+
+module inv(...);
+output o;
+input i;
+endmodule
+
+module top(...);
+input d0, d1, d2, d3;
+input clk;
+output q;
+ff4 #(.DATA_INV(4'h5)) ff_inst (.clk(clk), .d({d3, d2, d1, d0}), .q(q));
+endmodule
+
+EOT
+
+extractinv -inv inv o:i
+clean
+
+select -assert-count 2 top/t:inv
+select -assert-count 2 top/t:inv top/t:ff4 %ci:+[d] %ci:+[o] %i
+
+select -assert-count 1 top/t:inv top/w:d0 %co:+[i] %i
+select -assert-count 0 top/t:inv top/w:d1 %co:+[i] %i
+select -assert-count 1 top/t:inv top/w:d2 %co:+[i] %i
+select -assert-count 0 top/t:inv top/w:d3 %co:+[i] %i
+
+select -assert-count 0 top/t:ff4 top/w:d0 %co:+[d] %i
+select -assert-count 1 top/t:ff4 top/w:d1 %co:+[d] %i
+select -assert-count 0 top/t:ff4 top/w:d2 %co:+[d] %i
+select -assert-count 1 top/t:ff4 top/w:d3 %co:+[d] %i

From 13fa873f11c8332a10c1dda9e42c62b20e93c6b3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= <koriakin@0x04.net>
Date: Wed, 28 Aug 2019 15:28:01 +0000
Subject: [PATCH 3/4] Use extractinv for synth_xilinx -ise

---
 techlibs/xilinx/cells_sim.v       |  52 ++++++--
 techlibs/xilinx/cells_xtra.py     |  23 +++-
 techlibs/xilinx/synth_xilinx.cc   |   4 +-
 techlibs/xilinx/xc6s_cells_xtra.v |  33 +++--
 techlibs/xilinx/xc6v_cells_xtra.v | 114 ++++++++++++------
 techlibs/xilinx/xc7_brams_bb.v    |  16 +++
 techlibs/xilinx/xc7_cells_xtra.v  | 194 ++++++++++++++++++++++++------
 techlibs/xilinx/xcu_cells_xtra.v  | 156 ++++++++++++++++++++++++
 8 files changed, 502 insertions(+), 90 deletions(-)

diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v
index 6e8729256..ef4340d10 100644
--- a/techlibs/xilinx/cells_sim.v
+++ b/techlibs/xilinx/cells_sim.v
@@ -60,9 +60,18 @@ module BUFGCTRL(
     (* clkbuf_driver *)
     output O,
     input I0, input I1,
-    input S0, input S1,
-    input CE0, input CE1,
-    input IGNORE0, input IGNORE1);
+    (* invertible_pin = "IS_S0_INVERTED" *)
+    input S0,
+    (* invertible_pin = "IS_S1_INVERTED" *)
+    input S1,
+    (* invertible_pin = "IS_CE0_INVERTED" *)
+    input CE0,
+    (* invertible_pin = "IS_CE1_INVERTED" *)
+    input CE1,
+    (* invertible_pin = "IS_IGNORE0_INVERTED" *)
+    input IGNORE0,
+    (* invertible_pin = "IS_IGNORE1_INVERTED" *)
+    input IGNORE1);
 
 parameter [0:0] INIT_OUT = 1'b0;
 parameter PRESELECT_I0 = "FALSE";
@@ -87,6 +96,7 @@ module BUFHCE(
     (* clkbuf_driver *)
     output O,
     input I,
+    (* invertible_pin = "IS_CE_INVERTED" *)
     input CE);
 
 parameter [0:0] INIT_OUT = 1'b0;
@@ -234,8 +244,13 @@ module FDRE (
   (* abc_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
-  input C, 
-  input CE, D, R
+  (* invertible_pin = "IS_C_INVERTED" *)
+  input C,
+  input CE,
+  (* invertible_pin = "IS_D_INVERTED" *)
+  input D,
+  (* invertible_pin = "IS_R_INVERTED" *)
+  input R
 );
   parameter [0:0] INIT = 1'b0;
   parameter [0:0] IS_C_INVERTED = 1'b0;
@@ -252,8 +267,13 @@ module FDSE (
   (* abc_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
+  (* invertible_pin = "IS_C_INVERTED" *)
   input C,
-  input CE, D, S
+  input CE,
+  (* invertible_pin = "IS_D_INVERTED" *)
+  input D,
+  (* invertible_pin = "IS_S_INVERTED" *)
+  input S
 );
   parameter [0:0] INIT = 1'b1;
   parameter [0:0] IS_C_INVERTED = 1'b0;
@@ -270,8 +290,13 @@ module FDCE (
   (* abc_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
+  (* invertible_pin = "IS_C_INVERTED" *)
   input C,
-  input CE, D, CLR
+  input CE,
+  (* invertible_pin = "IS_D_INVERTED" *)
+  input D,
+  (* invertible_pin = "IS_CLR_INVERTED" *)
+  input CLR
 );
   parameter [0:0] INIT = 1'b0;
   parameter [0:0] IS_C_INVERTED = 1'b0;
@@ -290,8 +315,13 @@ module FDPE (
   (* abc_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
+  (* invertible_pin = "IS_C_INVERTED" *)
   input C,
-  input CE, D, PRE
+  input CE,
+  (* invertible_pin = "IS_D_INVERTED" *)
+  input D,
+  (* invertible_pin = "IS_PRE_INVERTED" *)
+  input PRE
 );
   parameter [0:0] INIT = 1'b1;
   parameter [0:0] IS_C_INVERTED = 1'b0;
@@ -360,6 +390,7 @@ module RAM32X1D (
   output DPO, SPO,
   input  D,
   (* clkbuf_sink *)
+  (* invertible_pin = "IS_WCLK_INVERTED" *)
   input  WCLK,
   input  WE,
   input  A0, A1, A2, A3, A4,
@@ -382,6 +413,7 @@ module RAM64X1D (
   output DPO, SPO,
   input  D,
   (* clkbuf_sink *)
+  (* invertible_pin = "IS_WCLK_INVERTED" *)
   input  WCLK,
   input  WE,
   input  A0, A1, A2, A3, A4, A5,
@@ -404,6 +436,7 @@ module RAM128X1D (
   output DPO, SPO,
   input        D,
   (* clkbuf_sink *)
+  (* invertible_pin = "IS_WCLK_INVERTED" *)
   input        WCLK,
   input        WE,
   input  [6:0] A, DPRA
@@ -423,6 +456,7 @@ module SRL16E (
   output Q,
   input A0, A1, A2, A3, CE,
   (* clkbuf_sink *)
+  (* invertible_pin = "IS_CLK_INVERTED" *)
   input CLK,
   input D
 );
@@ -445,6 +479,7 @@ module SRLC16E (
   output Q15,
   input A0, A1, A2, A3, CE,
   (* clkbuf_sink *)
+  (* invertible_pin = "IS_CLK_INVERTED" *)
   input CLK,
   input D
 );
@@ -472,6 +507,7 @@ module SRLC32E (
   input [4:0] A,
   input CE,
   (* clkbuf_sink *)
+  (* invertible_pin = "IS_CLK_INVERTED" *)
   input CLK,
   input D
 );
diff --git a/techlibs/xilinx/cells_xtra.py b/techlibs/xilinx/cells_xtra.py
index 4915f2a3e..561a61943 100644
--- a/techlibs/xilinx/cells_xtra.py
+++ b/techlibs/xilinx/cells_xtra.py
@@ -5,6 +5,7 @@ from io import StringIO
 from enum import Enum, auto
 import os.path
 import sys
+import re
 
 
 class Cell:
@@ -585,6 +586,8 @@ def xtract_cell_decl(cell, dirs, outf):
                 state = State.OUTSIDE
                 found = False
                 # Probably the most horrible Verilog "parser" ever written.
+                module_ports = []
+                invertible_ports = set()
                 for l in f:
                     l = l.partition('//')[0]
                     l = l.strip()
@@ -619,6 +622,15 @@ def xtract_cell_decl(cell, dirs, outf):
                             state = State.IN_MODULE
                     elif l == 'endmodule':
                         if state == State.IN_MODULE:
+                            for kind, rng, port in module_ports:
+                                for attr in cell.port_attrs.get(port, []):
+                                    outf.write('    (* {} *)\n'.format(attr))
+                                if port in invertible_ports:
+                                    outf.write('    (* invertible_pin = "IS_{}_INVERTED" *)\n'.format(port))
+                                if rng is None:
+                                    outf.write('    {} {};\n'.format(kind, port))
+                                else:
+                                    outf.write('    {} {} {};\n'.format(kind, rng, port))
                             outf.write(l + '\n')
                             outf.write('\n')
                         elif state != State.IN_OTHER_MODULE:
@@ -634,9 +646,11 @@ def xtract_cell_decl(cell, dirs, outf):
                         kind, _, ports = l.partition(' ')
                         for port in ports.split(','):
                             port = port.strip()
-                            for attr in cell.port_attrs.get(port, []):
-                                outf.write('    (* {} *)\n'.format(attr))
-                            outf.write('    {} {};\n'.format(kind, port))
+                            if port.startswith('['):
+                                rng, port = port.split()
+                            else:
+                                rng = None
+                            module_ports.append((kind, rng, port))
                     elif l.startswith('parameter ') and state == State.IN_MODULE:
                         if 'UNPLACED' in l:
                             continue
@@ -648,6 +662,9 @@ def xtract_cell_decl(cell, dirs, outf):
                             print('Weird parameter line in {} [{}].'.format(fname, l))
                             sys.exit(1)
                         outf.write('    {};\n'.format(l))
+                        match = re.search('IS_([a-zA-Z0-9_]+)_INVERTED', l)
+                        if match:
+                            invertible_ports.add(match[1])
                 if state != State.OUTSIDE:
                     print('endmodule not found in {}.'.format(fname))
                     sys.exit(1)
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index 7467e024c..173841799 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -485,8 +485,10 @@ struct SynthXilinxPass : public ScriptPass
 				else
 					run("clkbufmap -buf BUFG O:I");
 			}
-			if (do_iopad)
+			if (help_mode || do_iopad)
 				run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I A:top", "(only if '-iopad' or '-ise' and not '-noiopad')");
+			if (help_mode || ise)
+				run("extractinv -inv INV O:I", "(only if '-ise')");
 		}
 
 		if (check_label("check")) {
diff --git a/techlibs/xilinx/xc6s_cells_xtra.v b/techlibs/xilinx/xc6s_cells_xtra.v
index edf5739d6..014e73df0 100644
--- a/techlibs/xilinx/xc6s_cells_xtra.v
+++ b/techlibs/xilinx/xc6s_cells_xtra.v
@@ -559,7 +559,9 @@ module BUFGCE (...);
     parameter [0:0] IS_I_INVERTED = 1'b0;
     (* clkbuf_driver *)
     output O;
+    (* invertible_pin = "IS_CE_INVERTED" *)
     input CE;
+    (* invertible_pin = "IS_I_INVERTED" *)
     input I;
 endmodule
 
@@ -743,6 +745,7 @@ endmodule
 
 (* keep *)
 module BSCAN_SPARTAN6 (...);
+    parameter integer JTAG_CHAIN = 1;
     output CAPTURE;
     output DRCK;
     output RESET;
@@ -754,7 +757,6 @@ module BSCAN_SPARTAN6 (...);
     output TMS;
     output UPDATE;
     input TDO;
-    parameter integer JTAG_CHAIN = 1;
 endmodule
 
 module DNA_PORT (...);
@@ -1558,6 +1560,7 @@ module RAM128X1S (...);
     input A6;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -1569,6 +1572,7 @@ module RAM256X1S (...);
     input [7:0] A;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -1592,6 +1596,7 @@ module RAM32M (...);
     input [1:0] DIC;
     input [1:0] DID;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -1607,6 +1612,7 @@ module RAM32X1S (...);
     input A4;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -1622,6 +1628,7 @@ module RAM32X1S_1 (...);
     input A4;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -1640,6 +1647,7 @@ module RAM32X2S (...);
     input D0;
     input D1;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -1663,6 +1671,7 @@ module RAM64M (...);
     input DIC;
     input DID;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -1679,6 +1688,7 @@ module RAM64X1S (...);
     input A5;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -1695,6 +1705,7 @@ module RAM64X1S_1 (...);
     input A5;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -1714,6 +1725,7 @@ module RAM64X2S (...);
     input D0;
     input D1;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -1765,6 +1777,10 @@ module ROM64X1 (...);
 endmodule
 
 module IDDR2 (...);
+    parameter DDR_ALIGNMENT = "NONE";
+    parameter [0:0] INIT_Q0 = 1'b0;
+    parameter [0:0] INIT_Q1 = 1'b0;
+    parameter SRTYPE = "SYNC";
     output Q0;
     output Q1;
     (* clkbuf_sink *)
@@ -1775,10 +1791,6 @@ module IDDR2 (...);
     input D;
     input R;
     input S;
-    parameter DDR_ALIGNMENT = "NONE";
-    parameter [0:0] INIT_Q0 = 1'b0;
-    parameter [0:0] INIT_Q1 = 1'b0;
-    parameter SRTYPE = "SYNC";
 endmodule
 
 module LDCE (...);
@@ -1788,8 +1800,10 @@ module LDCE (...);
     parameter MSGON = "TRUE";
     parameter XON = "TRUE";
     output Q;
+    (* invertible_pin = "IS_CLR_INVERTED" *)
     input CLR;
     input D;
+    (* invertible_pin = "IS_G_INVERTED" *)
     input G;
     input GE;
 endmodule
@@ -1802,12 +1816,17 @@ module LDPE (...);
     parameter XON = "TRUE";
     output Q;
     input D;
+    (* invertible_pin = "IS_G_INVERTED" *)
     input G;
     input GE;
+    (* invertible_pin = "IS_PRE_INVERTED" *)
     input PRE;
 endmodule
 
 module ODDR2 (...);
+    parameter DDR_ALIGNMENT = "NONE";
+    parameter [0:0] INIT = 1'b0;
+    parameter SRTYPE = "SYNC";
     output Q;
     (* clkbuf_sink *)
     input C0;
@@ -1818,9 +1837,6 @@ module ODDR2 (...);
     input D1;
     input R;
     input S;
-    parameter DDR_ALIGNMENT = "NONE";
-    parameter [0:0] INIT = 1'b0;
-    parameter SRTYPE = "SYNC";
 endmodule
 
 module CFGLUT5 (...);
@@ -1837,6 +1853,7 @@ module CFGLUT5 (...);
     input CDI;
     input CE;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
 endmodule
 
diff --git a/techlibs/xilinx/xc6v_cells_xtra.v b/techlibs/xilinx/xc6v_cells_xtra.v
index 3e2336eda..263bcc69d 100644
--- a/techlibs/xilinx/xc6v_cells_xtra.v
+++ b/techlibs/xilinx/xc6v_cells_xtra.v
@@ -596,29 +596,6 @@ module PCIE_2_0 (...);
 endmodule
 
 module SYSMON (...);
-    output BUSY;
-    output DRDY;
-    output EOC;
-    output EOS;
-    output JTAGBUSY;
-    output JTAGLOCKED;
-    output JTAGMODIFIED;
-    output OT;
-    output [15:0] DO;
-    output [2:0] ALM;
-    output [4:0] CHANNEL;
-    input CONVST;
-    input CONVSTCLK;
-    input DCLK;
-    input DEN;
-    input DWE;
-    input RESET;
-    input VN;
-    input VP;
-    input [15:0] DI;
-    input [15:0] VAUXN;
-    input [15:0] VAUXP;
-    input [6:0] DADDR;
     parameter [15:0] INIT_40 = 16'h0;
     parameter [15:0] INIT_41 = 16'h0;
     parameter [15:0] INIT_42 = 16'h0800;
@@ -645,6 +622,29 @@ module SYSMON (...);
     parameter [15:0] INIT_57 = 16'h0;
     parameter SIM_DEVICE = "VIRTEX5";
     parameter SIM_MONITOR_FILE = "design.txt";
+    output BUSY;
+    output DRDY;
+    output EOC;
+    output EOS;
+    output JTAGBUSY;
+    output JTAGLOCKED;
+    output JTAGMODIFIED;
+    output OT;
+    output [15:0] DO;
+    output [2:0] ALM;
+    output [4:0] CHANNEL;
+    input CONVST;
+    input CONVSTCLK;
+    input DCLK;
+    input DEN;
+    input DWE;
+    input RESET;
+    input VN;
+    input VP;
+    input [15:0] DI;
+    input [15:0] VAUXN;
+    input [15:0] VAUXP;
+    input [6:0] DADDR;
 endmodule
 
 module DSP48E1 (...);
@@ -691,11 +691,13 @@ module DSP48E1 (...);
     output UNDERFLOW;
     input [29:0] A;
     input [29:0] ACIN;
+    (* invertible_pin = "IS_ALUMODE_INVERTED" *)
     input [3:0] ALUMODE;
     input [17:0] B;
     input [17:0] BCIN;
     input [47:0] C;
     input CARRYCASCIN;
+    (* invertible_pin = "IS_CARRYIN_INVERTED" *)
     input CARRYIN;
     input [2:0] CARRYINSEL;
     input CEA1;
@@ -712,10 +714,13 @@ module DSP48E1 (...);
     input CEM;
     input CEP;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
     input [24:0] D;
+    (* invertible_pin = "IS_INMODE_INVERTED" *)
     input [4:0] INMODE;
     input MULTSIGNIN;
+    (* invertible_pin = "IS_OPMODE_INVERTED" *)
     input [6:0] OPMODE;
     input [47:0] PCIN;
     input RSTA;
@@ -736,7 +741,9 @@ module BUFGCE (...);
     parameter [0:0] IS_I_INVERTED = 1'b0;
     (* clkbuf_driver *)
     output O;
+    (* invertible_pin = "IS_CE_INVERTED" *)
     input CE;
+    (* invertible_pin = "IS_I_INVERTED" *)
     input I;
 endmodule
 
@@ -794,13 +801,13 @@ module BUFIODQS (...);
 endmodule
 
 module BUFR (...);
+    parameter BUFR_DIVIDE = "BYPASS";
+    parameter SIM_DEVICE = "7SERIES";
     (* clkbuf_driver *)
     output O;
     input CE;
     input CLR;
     input I;
-    parameter BUFR_DIVIDE = "BYPASS";
-    parameter SIM_DEVICE = "7SERIES";
 endmodule
 
 module IBUFDS_GTXE1 (...);
@@ -952,6 +959,8 @@ endmodule
 
 (* keep *)
 module BSCAN_VIRTEX6 (...);
+    parameter DISABLE_JTAG = "FALSE";
+    parameter integer JTAG_CHAIN = 1;
     output CAPTURE;
     output DRCK;
     output RESET;
@@ -963,15 +972,13 @@ module BSCAN_VIRTEX6 (...);
     output TMS;
     output UPDATE;
     input TDO;
-    parameter DISABLE_JTAG = "FALSE";
-    parameter integer JTAG_CHAIN = 1;
 endmodule
 
 (* keep *)
 module CAPTURE_VIRTEX6 (...);
+    parameter ONESHOT = "TRUE";
     input CAP;
     input CLK;
-    parameter ONESHOT = "TRUE";
 endmodule
 
 module DNA_PORT (...);
@@ -2299,13 +2306,19 @@ module FIFO18E1 (...);
     input [31:0] DI;
     input [3:0] DIP;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_RDCLK_INVERTED" *)
     input RDCLK;
+    (* invertible_pin = "IS_RDEN_INVERTED" *)
     input RDEN;
     input REGCE;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
+    (* invertible_pin = "IS_RSTREG_INVERTED" *)
     input RSTREG;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WRCLK_INVERTED" *)
     input WRCLK;
+    (* invertible_pin = "IS_WREN_INVERTED" *)
     input WREN;
 endmodule
 
@@ -2346,13 +2359,19 @@ module FIFO36E1 (...);
     input INJECTDBITERR;
     input INJECTSBITERR;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_RDCLK_INVERTED" *)
     input RDCLK;
+    (* invertible_pin = "IS_RDEN_INVERTED" *)
     input RDEN;
     input REGCE;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
+    (* invertible_pin = "IS_RSTREG_INVERTED" *)
     input RSTREG;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WRCLK_INVERTED" *)
     input WRCLK;
+    (* invertible_pin = "IS_WREN_INVERTED" *)
     input WREN;
 endmodule
 
@@ -2369,6 +2388,7 @@ module RAM128X1S (...);
     input A6;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -2380,6 +2400,7 @@ module RAM256X1S (...);
     input [7:0] A;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -2403,6 +2424,7 @@ module RAM32M (...);
     input [1:0] DIC;
     input [1:0] DID;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -2418,6 +2440,7 @@ module RAM32X1S (...);
     input A4;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -2433,6 +2456,7 @@ module RAM32X1S_1 (...);
     input A4;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -2451,6 +2475,7 @@ module RAM32X2S (...);
     input D0;
     input D1;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -2474,6 +2499,7 @@ module RAM64M (...);
     input DIC;
     input DID;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -2490,6 +2516,7 @@ module RAM64X1S (...);
     input A5;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -2506,6 +2533,7 @@ module RAM64X1S_1 (...);
     input A5;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -2525,6 +2553,7 @@ module RAM64X2S (...);
     input D0;
     input D1;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -2587,8 +2616,10 @@ module IDDR (...);
     output Q1;
     output Q2;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_C_INVERTED" *)
     input C;
     input CE;
+    (* invertible_pin = "IS_D_INVERTED" *)
     input D;
     input R;
     input S;
@@ -2605,10 +2636,13 @@ module IDDR_2CLK (...);
     output Q1;
     output Q2;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_C_INVERTED" *)
     input C;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CB_INVERTED" *)
     input CB;
     input CE;
+    (* invertible_pin = "IS_D_INVERTED" *)
     input D;
     input R;
     input S;
@@ -2621,8 +2655,10 @@ module LDCE (...);
     parameter MSGON = "TRUE";
     parameter XON = "TRUE";
     output Q;
+    (* invertible_pin = "IS_CLR_INVERTED" *)
     input CLR;
     input D;
+    (* invertible_pin = "IS_G_INVERTED" *)
     input G;
     input GE;
 endmodule
@@ -2635,20 +2671,14 @@ module LDPE (...);
     parameter XON = "TRUE";
     output Q;
     input D;
+    (* invertible_pin = "IS_G_INVERTED" *)
     input G;
     input GE;
+    (* invertible_pin = "IS_PRE_INVERTED" *)
     input PRE;
 endmodule
 
 module ODDR (...);
-    output Q;
-    (* clkbuf_sink *)
-    input C;
-    input CE;
-    input D1;
-    input D2;
-    input R;
-    input S;
     parameter DDR_CLK_EDGE = "OPPOSITE_EDGE";
     parameter INIT = 1'b0;
     parameter [0:0] IS_C_INVERTED = 1'b0;
@@ -2657,6 +2687,17 @@ module ODDR (...);
     parameter SRTYPE = "SYNC";
     parameter MSGON = "TRUE";
     parameter XON = "TRUE";
+    output Q;
+    (* clkbuf_sink *)
+    (* invertible_pin = "IS_C_INVERTED" *)
+    input C;
+    input CE;
+    (* invertible_pin = "IS_D1_INVERTED" *)
+    input D1;
+    (* invertible_pin = "IS_D2_INVERTED" *)
+    input D2;
+    input R;
+    input S;
 endmodule
 
 module CFGLUT5 (...);
@@ -2673,6 +2714,7 @@ module CFGLUT5 (...);
     input CDI;
     input CE;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
 endmodule
 
diff --git a/techlibs/xilinx/xc7_brams_bb.v b/techlibs/xilinx/xc7_brams_bb.v
index 5b40a457d..a28ba5b14 100644
--- a/techlibs/xilinx/xc7_brams_bb.v
+++ b/techlibs/xilinx/xc7_brams_bb.v
@@ -2,16 +2,24 @@
 
 module RAMB18E1 (
 	(* clkbuf_sink *)
+	(* invertible_pin = "IS_CLKARDCLK_INVERTED" *)
 	input CLKARDCLK,
 	(* clkbuf_sink *)
+	(* invertible_pin = "IS_CLKBWRCLK_INVERTED" *)
 	input CLKBWRCLK,
+	(* invertible_pin = "IS_ENARDEN_INVERTED" *)
 	input ENARDEN,
+	(* invertible_pin = "IS_ENBWREN_INVERTED" *)
 	input ENBWREN,
 	input REGCEAREGCE,
 	input REGCEB,
+	(* invertible_pin = "IS_RSTRAMARSTRAM_INVERTED" *)
 	input RSTRAMARSTRAM,
+	(* invertible_pin = "IS_RSTRAMB_INVERTED" *)
 	input RSTRAMB,
+	(* invertible_pin = "IS_RSTREGARSTREG_INVERTED" *)
 	input RSTREGARSTREG,
+	(* invertible_pin = "IS_RSTREGB_INVERTED" *)
 	input RSTREGB,
 
 	input [13:0] ADDRARDADDR,
@@ -132,16 +140,24 @@ endmodule
 
 module RAMB36E1 (
 	(* clkbuf_sink *)
+	(* invertible_pin = "IS_CLKARDCLK_INVERTED" *)
 	input CLKARDCLK,
 	(* clkbuf_sink *)
+	(* invertible_pin = "IS_CLKBWRCLK_INVERTED" *)
 	input CLKBWRCLK,
+	(* invertible_pin = "IS_ENARDEN_INVERTED" *)
 	input ENARDEN,
+	(* invertible_pin = "IS_ENBWREN_INVERTED" *)
 	input ENBWREN,
 	input REGCEAREGCE,
 	input REGCEB,
+	(* invertible_pin = "IS_RSTRAMARSTRAM_INVERTED" *)
 	input RSTRAMARSTRAM,
+	(* invertible_pin = "IS_RSTRAMB_INVERTED" *)
 	input RSTRAMB,
+	(* invertible_pin = "IS_RSTREGARSTREG_INVERTED" *)
 	input RSTREGARSTREG,
+	(* invertible_pin = "IS_RSTREGB_INVERTED" *)
 	input RSTREGB,
 
 	input [15:0] ADDRARDADDR,
diff --git a/techlibs/xilinx/xc7_cells_xtra.v b/techlibs/xilinx/xc7_cells_xtra.v
index e42413153..817932e9f 100644
--- a/techlibs/xilinx/xc7_cells_xtra.v
+++ b/techlibs/xilinx/xc7_cells_xtra.v
@@ -347,20 +347,26 @@ module GTHE2_CHANNEL (...);
     output [7:0] RXDISPERR;
     output [7:0] RXNOTINTABLE;
     input CFGRESET;
+    (* invertible_pin = "IS_CLKRSVD0_INVERTED" *)
     input CLKRSVD0;
+    (* invertible_pin = "IS_CLKRSVD1_INVERTED" *)
     input CLKRSVD1;
+    (* invertible_pin = "IS_CPLLLOCKDETCLK_INVERTED" *)
     input CPLLLOCKDETCLK;
     input CPLLLOCKEN;
     input CPLLPD;
     input CPLLRESET;
     input DMONFIFORESET;
+    (* invertible_pin = "IS_DMONITORCLK_INVERTED" *)
     input DMONITORCLK;
+    (* invertible_pin = "IS_DRPCLK_INVERTED" *)
     input DRPCLK;
     input DRPEN;
     input DRPWE;
     input EYESCANMODE;
     input EYESCANRESET;
     input EYESCANTRIGGER;
+    (* invertible_pin = "IS_GTGREFCLK_INVERTED" *)
     input GTGREFCLK;
     input GTHRXN;
     input GTHRXP;
@@ -456,9 +462,12 @@ module GTHE2_CHANNEL (...);
     input RXSYNCIN;
     input RXSYNCMODE;
     input RXUSERRDY;
+    (* invertible_pin = "IS_RXUSRCLK2_INVERTED" *)
     input RXUSRCLK2;
+    (* invertible_pin = "IS_RXUSRCLK_INVERTED" *)
     input RXUSRCLK;
     input SETERRSTATUS;
+    (* invertible_pin = "IS_SIGVALIDCLK_INVERTED" *)
     input SIGVALIDCLK;
     input TX8B10BEN;
     input TXCOMINIT;
@@ -481,6 +490,7 @@ module GTHE2_CHANNEL (...);
     input TXPHALIGNEN;
     input TXPHDLYPD;
     input TXPHDLYRESET;
+    (* invertible_pin = "IS_TXPHDLYTSTCLK_INVERTED" *)
     input TXPHDLYTSTCLK;
     input TXPHINIT;
     input TXPHOVRDEN;
@@ -504,7 +514,9 @@ module GTHE2_CHANNEL (...);
     input TXSYNCIN;
     input TXSYNCMODE;
     input TXUSERRDY;
+    (* invertible_pin = "IS_TXUSRCLK2_INVERTED" *)
     input TXUSRCLK2;
+    (* invertible_pin = "IS_TXUSRCLK_INVERTED" *)
     input TXUSRCLK;
     input [13:0] RXADAPTSELTEST;
     input [15:0] DRPDI;
@@ -593,9 +605,11 @@ module GTHE2_COMMON (...);
     input BGMONITORENB;
     input BGPDB;
     input BGRCALOVRDENB;
+    (* invertible_pin = "IS_DRPCLK_INVERTED" *)
     input DRPCLK;
     input DRPEN;
     input DRPWE;
+    (* invertible_pin = "IS_GTGREFCLK_INVERTED" *)
     input GTGREFCLK;
     input GTNORTHREFCLK0;
     input GTNORTHREFCLK1;
@@ -603,6 +617,7 @@ module GTHE2_COMMON (...);
     input GTREFCLK1;
     input GTSOUTHREFCLK0;
     input GTSOUTHREFCLK1;
+    (* invertible_pin = "IS_QPLLLOCKDETCLK_INVERTED" *)
     input QPLLLOCKDETCLK;
     input QPLLLOCKEN;
     input QPLLOUTRESET;
@@ -928,10 +943,14 @@ module GTPE2_CHANNEL (...);
     output [4:0] RXPHMONITOR;
     output [4:0] RXPHSLIPMONITOR;
     input CFGRESET;
+    (* invertible_pin = "IS_CLKRSVD0_INVERTED" *)
     input CLKRSVD0;
+    (* invertible_pin = "IS_CLKRSVD1_INVERTED" *)
     input CLKRSVD1;
     input DMONFIFORESET;
+    (* invertible_pin = "IS_DMONITORCLK_INVERTED" *)
     input DMONITORCLK;
+    (* invertible_pin = "IS_DRPCLK_INVERTED" *)
     input DRPCLK;
     input DRPEN;
     input DRPWE;
@@ -1005,9 +1024,12 @@ module GTPE2_CHANNEL (...);
     input RXSYNCIN;
     input RXSYNCMODE;
     input RXUSERRDY;
+    (* invertible_pin = "IS_RXUSRCLK2_INVERTED" *)
     input RXUSRCLK2;
+    (* invertible_pin = "IS_RXUSRCLK_INVERTED" *)
     input RXUSRCLK;
     input SETERRSTATUS;
+    (* invertible_pin = "IS_SIGVALIDCLK_INVERTED" *)
     input SIGVALIDCLK;
     input TX8B10BEN;
     input TXCOMINIT;
@@ -1030,6 +1052,7 @@ module GTPE2_CHANNEL (...);
     input TXPHALIGNEN;
     input TXPHDLYPD;
     input TXPHDLYRESET;
+    (* invertible_pin = "IS_TXPHDLYTSTCLK_INVERTED" *)
     input TXPHDLYTSTCLK;
     input TXPHINIT;
     input TXPHOVRDEN;
@@ -1050,7 +1073,9 @@ module GTPE2_CHANNEL (...);
     input TXSYNCIN;
     input TXSYNCMODE;
     input TXUSERRDY;
+    (* invertible_pin = "IS_TXUSRCLK2_INVERTED" *)
     input TXUSRCLK2;
+    (* invertible_pin = "IS_TXUSRCLK_INVERTED" *)
     input TXUSRCLK;
     input [13:0] RXADAPTSELTEST;
     input [15:0] DRPDI;
@@ -1139,21 +1164,26 @@ module GTPE2_COMMON (...);
     input BGMONITORENB;
     input BGPDB;
     input BGRCALOVRDENB;
+    (* invertible_pin = "IS_DRPCLK_INVERTED" *)
     input DRPCLK;
     input DRPEN;
     input DRPWE;
     input GTEASTREFCLK0;
     input GTEASTREFCLK1;
+    (* invertible_pin = "IS_GTGREFCLK0_INVERTED" *)
     input GTGREFCLK0;
+    (* invertible_pin = "IS_GTGREFCLK1_INVERTED" *)
     input GTGREFCLK1;
     input GTREFCLK0;
     input GTREFCLK1;
     input GTWESTREFCLK0;
     input GTWESTREFCLK1;
+    (* invertible_pin = "IS_PLL0LOCKDETCLK_INVERTED" *)
     input PLL0LOCKDETCLK;
     input PLL0LOCKEN;
     input PLL0PD;
     input PLL0RESET;
+    (* invertible_pin = "IS_PLL1LOCKDETCLK_INVERTED" *)
     input PLL1LOCKDETCLK;
     input PLL1LOCKEN;
     input PLL1PD;
@@ -1442,16 +1472,19 @@ module GTXE2_CHANNEL (...);
     output [7:0] RXNOTINTABLE;
     output [9:0] TSTOUT;
     input CFGRESET;
+    (* invertible_pin = "IS_CPLLLOCKDETCLK_INVERTED" *)
     input CPLLLOCKDETCLK;
     input CPLLLOCKEN;
     input CPLLPD;
     input CPLLRESET;
+    (* invertible_pin = "IS_DRPCLK_INVERTED" *)
     input DRPCLK;
     input DRPEN;
     input DRPWE;
     input EYESCANMODE;
     input EYESCANRESET;
     input EYESCANTRIGGER;
+    (* invertible_pin = "IS_GTGREFCLK_INVERTED" *)
     input GTGREFCLK;
     input GTNORTHREFCLK0;
     input GTNORTHREFCLK1;
@@ -1528,7 +1561,9 @@ module GTXE2_CHANNEL (...);
     input RXQPIEN;
     input RXSLIDE;
     input RXUSERRDY;
+    (* invertible_pin = "IS_RXUSRCLK2_INVERTED" *)
     input RXUSRCLK2;
+    (* invertible_pin = "IS_RXUSRCLK_INVERTED" *)
     input RXUSRCLK;
     input SETERRSTATUS;
     input TX8B10BEN;
@@ -1552,6 +1587,7 @@ module GTXE2_CHANNEL (...);
     input TXPHALIGNEN;
     input TXPHDLYPD;
     input TXPHDLYRESET;
+    (* invertible_pin = "IS_TXPHDLYTSTCLK_INVERTED" *)
     input TXPHDLYTSTCLK;
     input TXPHINIT;
     input TXPHOVRDEN;
@@ -1567,7 +1603,9 @@ module GTXE2_CHANNEL (...);
     input TXSTARTSEQ;
     input TXSWING;
     input TXUSERRDY;
+    (* invertible_pin = "IS_TXUSRCLK2_INVERTED" *)
     input TXUSRCLK2;
+    (* invertible_pin = "IS_TXUSRCLK_INVERTED" *)
     input TXUSRCLK;
     input [15:0] DRPDI;
     input [15:0] GTRSVD;
@@ -1644,9 +1682,11 @@ module GTXE2_COMMON (...);
     input BGBYPASSB;
     input BGMONITORENB;
     input BGPDB;
+    (* invertible_pin = "IS_DRPCLK_INVERTED" *)
     input DRPCLK;
     input DRPEN;
     input DRPWE;
+    (* invertible_pin = "IS_GTGREFCLK_INVERTED" *)
     input GTGREFCLK;
     input GTNORTHREFCLK0;
     input GTNORTHREFCLK1;
@@ -1654,6 +1694,7 @@ module GTXE2_COMMON (...);
     input GTREFCLK1;
     input GTSOUTHREFCLK0;
     input GTSOUTHREFCLK1;
+    (* invertible_pin = "IS_QPLLLOCKDETCLK_INVERTED" *)
     input QPLLLOCKDETCLK;
     input QPLLLOCKEN;
     input QPLLOUTRESET;
@@ -3271,30 +3312,6 @@ module PCIE_3_0 (...);
 endmodule
 
 module XADC (...);
-    output BUSY;
-    output DRDY;
-    output EOC;
-    output EOS;
-    output JTAGBUSY;
-    output JTAGLOCKED;
-    output JTAGMODIFIED;
-    output OT;
-    output [15:0] DO;
-    output [7:0] ALM;
-    output [4:0] CHANNEL;
-    output [4:0] MUXADDR;
-    input CONVST;
-    input CONVSTCLK;
-    input DCLK;
-    input DEN;
-    input DWE;
-    input RESET;
-    input VN;
-    input VP;
-    input [15:0] DI;
-    input [15:0] VAUXN;
-    input [15:0] VAUXP;
-    input [6:0] DADDR;
     parameter [15:0] INIT_40 = 16'h0;
     parameter [15:0] INIT_41 = 16'h0;
     parameter [15:0] INIT_42 = 16'h0800;
@@ -3331,6 +3348,32 @@ module XADC (...);
     parameter IS_DCLK_INVERTED = 1'b0;
     parameter SIM_DEVICE = "7SERIES";
     parameter SIM_MONITOR_FILE = "design.txt";
+    output BUSY;
+    output DRDY;
+    output EOC;
+    output EOS;
+    output JTAGBUSY;
+    output JTAGLOCKED;
+    output JTAGMODIFIED;
+    output OT;
+    output [15:0] DO;
+    output [7:0] ALM;
+    output [4:0] CHANNEL;
+    output [4:0] MUXADDR;
+    input CONVST;
+    (* invertible_pin = "IS_CONVSTCLK_INVERTED" *)
+    input CONVSTCLK;
+    (* invertible_pin = "IS_DCLK_INVERTED" *)
+    input DCLK;
+    input DEN;
+    input DWE;
+    input RESET;
+    input VN;
+    input VP;
+    input [15:0] DI;
+    input [15:0] VAUXN;
+    input [15:0] VAUXP;
+    input [6:0] DADDR;
 endmodule
 
 module DSP48E1 (...);
@@ -3377,11 +3420,13 @@ module DSP48E1 (...);
     output UNDERFLOW;
     input [29:0] A;
     input [29:0] ACIN;
+    (* invertible_pin = "IS_ALUMODE_INVERTED" *)
     input [3:0] ALUMODE;
     input [17:0] B;
     input [17:0] BCIN;
     input [47:0] C;
     input CARRYCASCIN;
+    (* invertible_pin = "IS_CARRYIN_INVERTED" *)
     input CARRYIN;
     input [2:0] CARRYINSEL;
     input CEA1;
@@ -3398,10 +3443,13 @@ module DSP48E1 (...);
     input CEM;
     input CEP;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
     input [24:0] D;
+    (* invertible_pin = "IS_INMODE_INVERTED" *)
     input [4:0] INMODE;
     input MULTSIGNIN;
+    (* invertible_pin = "IS_OPMODE_INVERTED" *)
     input [6:0] OPMODE;
     input [47:0] PCIN;
     input RSTA;
@@ -3422,7 +3470,9 @@ module BUFGCE (...);
     parameter [0:0] IS_I_INVERTED = 1'b0;
     (* clkbuf_driver *)
     output O;
+    (* invertible_pin = "IS_CE_INVERTED" *)
     input CE;
+    (* invertible_pin = "IS_I_INVERTED" *)
     input I;
 endmodule
 
@@ -3483,18 +3533,19 @@ module BUFMRCE (...);
     parameter [0:0] IS_CE_INVERTED = 1'b0;
     (* clkbuf_driver *)
     output O;
+    (* invertible_pin = "IS_CE_INVERTED" *)
     input CE;
     input I;
 endmodule
 
 module BUFR (...);
+    parameter BUFR_DIVIDE = "BYPASS";
+    parameter SIM_DEVICE = "7SERIES";
     (* clkbuf_driver *)
     output O;
     input CE;
     input CLR;
     input I;
-    parameter BUFR_DIVIDE = "BYPASS";
-    parameter SIM_DEVICE = "7SERIES";
 endmodule
 
 module MMCME2_ADV (...);
@@ -3575,6 +3626,7 @@ module MMCME2_ADV (...);
     input CLKFBIN;
     input CLKIN1;
     input CLKIN2;
+    (* invertible_pin = "IS_CLKINSEL_INVERTED" *)
     input CLKINSEL;
     input [6:0] DADDR;
     input DCLK;
@@ -3582,9 +3634,13 @@ module MMCME2_ADV (...);
     input [15:0] DI;
     input DWE;
     input PSCLK;
+    (* invertible_pin = "IS_PSEN_INVERTED" *)
     input PSEN;
+    (* invertible_pin = "IS_PSINCDEC_INVERTED" *)
     input PSINCDEC;
+    (* invertible_pin = "IS_PWRDWN_INVERTED" *)
     input PWRDWN;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
 endmodule
 
@@ -3689,11 +3745,14 @@ module PLLE2_ADV (...);
     input CLKFBIN;
     input CLKIN1;
     input CLKIN2;
+    (* invertible_pin = "IS_CLKINSEL_INVERTED" *)
     input CLKINSEL;
     input DCLK;
     input DEN;
     input DWE;
+    (* invertible_pin = "IS_PWRDWN_INVERTED" *)
     input PWRDWN;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
     input [15:0] DI;
     input [6:0] DADDR;
@@ -4022,11 +4081,14 @@ module IDELAYE2 (...);
     output [4:0] CNTVALUEOUT;
     output DATAOUT;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_C_INVERTED" *)
     input C;
     input CE;
     input CINVCTRL;
     input [4:0] CNTVALUEIN;
+    (* invertible_pin = "IS_DATAIN_INVERTED" *)
     input DATAIN;
+    (* invertible_pin = "IS_IDATAIN_INVERTED" *)
     input IDATAIN;
     input INC;
     input LD;
@@ -4264,20 +4326,27 @@ module ISERDESE2 (...);
     input CE1;
     input CE2;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLKB_INVERTED" *)
     input CLKB;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLKDIV_INVERTED" *)
     input CLKDIV;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLKDIVP_INVERTED" *)
     input CLKDIVP;
+    (* invertible_pin = "IS_D_INVERTED" *)
     input D;
     input DDLY;
     input DYNCLKDIVSEL;
     input DYNCLKSEL;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_OCLK_INVERTED" *)
     input OCLK;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_OCLKB_INVERTED" *)
     input OCLKB;
     input OFB;
     input RST;
@@ -4338,6 +4407,7 @@ module ODELAYE2 (...);
     output [4:0] CNTVALUEOUT;
     output DATAOUT;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_C_INVERTED" *)
     input C;
     input CE;
     input CINVCTRL;
@@ -4346,6 +4416,7 @@ module ODELAYE2 (...);
     input INC;
     input LD;
     input LDPIPEEN;
+    (* invertible_pin = "IS_ODATAIN_INVERTED" *)
     input ODATAIN;
     input REGRST;
 endmodule
@@ -4384,24 +4455,38 @@ module OSERDESE2 (...);
     output TFB;
     output TQ;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLKDIV_INVERTED" *)
     input CLKDIV;
+    (* invertible_pin = "IS_D1_INVERTED" *)
     input D1;
+    (* invertible_pin = "IS_D2_INVERTED" *)
     input D2;
+    (* invertible_pin = "IS_D3_INVERTED" *)
     input D3;
+    (* invertible_pin = "IS_D4_INVERTED" *)
     input D4;
+    (* invertible_pin = "IS_D5_INVERTED" *)
     input D5;
+    (* invertible_pin = "IS_D6_INVERTED" *)
     input D6;
+    (* invertible_pin = "IS_D7_INVERTED" *)
     input D7;
+    (* invertible_pin = "IS_D8_INVERTED" *)
     input D8;
     input OCE;
     input RST;
     input SHIFTIN1;
     input SHIFTIN2;
+    (* invertible_pin = "IS_T1_INVERTED" *)
     input T1;
+    (* invertible_pin = "IS_T2_INVERTED" *)
     input T2;
+    (* invertible_pin = "IS_T3_INVERTED" *)
     input T3;
+    (* invertible_pin = "IS_T4_INVERTED" *)
     input T4;
     input TBYTEIN;
     input TCE;
@@ -4474,6 +4559,7 @@ module PHASER_IN (...);
     input FREQREFCLK;
     input MEMREFCLK;
     input PHASEREFCLK;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
     input SYNCIN;
     input SYSCLK;
@@ -4515,6 +4601,7 @@ module PHASER_IN_PHY (...);
     input FREQREFCLK;
     input MEMREFCLK;
     input PHASEREFCLK;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
     input RSTDQSFIND;
     input SYNCIN;
@@ -4557,6 +4644,7 @@ module PHASER_OUT (...);
     input FREQREFCLK;
     input MEMREFCLK;
     input PHASEREFCLK;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
     input SELFINEOCLKDELAY;
     input SYNCIN;
@@ -4601,6 +4689,7 @@ module PHASER_OUT_PHY (...);
     input FREQREFCLK;
     input MEMREFCLK;
     input PHASEREFCLK;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
     input SELFINEOCLKDELAY;
     input SYNCIN;
@@ -4614,7 +4703,9 @@ module PHASER_REF (...);
     parameter [0:0] IS_PWRDWN_INVERTED = 1'b0;
     output LOCKED;
     input CLKIN;
+    (* invertible_pin = "IS_PWRDWN_INVERTED" *)
     input PWRDWN;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
 endmodule
 
@@ -4716,13 +4807,19 @@ module FIFO18E1 (...);
     input [31:0] DI;
     input [3:0] DIP;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_RDCLK_INVERTED" *)
     input RDCLK;
+    (* invertible_pin = "IS_RDEN_INVERTED" *)
     input RDEN;
     input REGCE;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
+    (* invertible_pin = "IS_RSTREG_INVERTED" *)
     input RSTREG;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WRCLK_INVERTED" *)
     input WRCLK;
+    (* invertible_pin = "IS_WREN_INVERTED" *)
     input WREN;
 endmodule
 
@@ -4763,13 +4860,19 @@ module FIFO36E1 (...);
     input INJECTDBITERR;
     input INJECTSBITERR;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_RDCLK_INVERTED" *)
     input RDCLK;
+    (* invertible_pin = "IS_RDEN_INVERTED" *)
     input RDEN;
     input REGCE;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
+    (* invertible_pin = "IS_RSTREG_INVERTED" *)
     input RSTREG;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WRCLK_INVERTED" *)
     input WRCLK;
+    (* invertible_pin = "IS_WREN_INVERTED" *)
     input WREN;
 endmodule
 
@@ -4786,6 +4889,7 @@ module RAM128X1S (...);
     input A6;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -4797,6 +4901,7 @@ module RAM256X1S (...);
     input [7:0] A;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -4820,6 +4925,7 @@ module RAM32M (...);
     input [1:0] DIC;
     input [1:0] DID;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -4835,6 +4941,7 @@ module RAM32X1S (...);
     input A4;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -4850,6 +4957,7 @@ module RAM32X1S_1 (...);
     input A4;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -4868,6 +4976,7 @@ module RAM32X2S (...);
     input D0;
     input D1;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -4891,6 +5000,7 @@ module RAM64M (...);
     input DIC;
     input DID;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -4907,6 +5017,7 @@ module RAM64X1S (...);
     input A5;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -4923,6 +5034,7 @@ module RAM64X1S_1 (...);
     input A5;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -4942,6 +5054,7 @@ module RAM64X2S (...);
     input D0;
     input D1;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -5004,8 +5117,10 @@ module IDDR (...);
     output Q1;
     output Q2;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_C_INVERTED" *)
     input C;
     input CE;
+    (* invertible_pin = "IS_D_INVERTED" *)
     input D;
     input R;
     input S;
@@ -5022,10 +5137,13 @@ module IDDR_2CLK (...);
     output Q1;
     output Q2;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_C_INVERTED" *)
     input C;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CB_INVERTED" *)
     input CB;
     input CE;
+    (* invertible_pin = "IS_D_INVERTED" *)
     input D;
     input R;
     input S;
@@ -5038,8 +5156,10 @@ module LDCE (...);
     parameter MSGON = "TRUE";
     parameter XON = "TRUE";
     output Q;
+    (* invertible_pin = "IS_CLR_INVERTED" *)
     input CLR;
     input D;
+    (* invertible_pin = "IS_G_INVERTED" *)
     input G;
     input GE;
 endmodule
@@ -5052,20 +5172,14 @@ module LDPE (...);
     parameter XON = "TRUE";
     output Q;
     input D;
+    (* invertible_pin = "IS_G_INVERTED" *)
     input G;
     input GE;
+    (* invertible_pin = "IS_PRE_INVERTED" *)
     input PRE;
 endmodule
 
 module ODDR (...);
-    output Q;
-    (* clkbuf_sink *)
-    input C;
-    input CE;
-    input D1;
-    input D2;
-    input R;
-    input S;
     parameter DDR_CLK_EDGE = "OPPOSITE_EDGE";
     parameter INIT = 1'b0;
     parameter [0:0] IS_C_INVERTED = 1'b0;
@@ -5074,6 +5188,17 @@ module ODDR (...);
     parameter SRTYPE = "SYNC";
     parameter MSGON = "TRUE";
     parameter XON = "TRUE";
+    output Q;
+    (* clkbuf_sink *)
+    (* invertible_pin = "IS_C_INVERTED" *)
+    input C;
+    input CE;
+    (* invertible_pin = "IS_D1_INVERTED" *)
+    input D1;
+    (* invertible_pin = "IS_D2_INVERTED" *)
+    input D2;
+    input R;
+    input S;
 endmodule
 
 module CFGLUT5 (...);
@@ -5090,6 +5215,7 @@ module CFGLUT5 (...);
     input CDI;
     input CE;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
 endmodule
 
diff --git a/techlibs/xilinx/xcu_cells_xtra.v b/techlibs/xilinx/xcu_cells_xtra.v
index 1f08879e2..2d331a221 100644
--- a/techlibs/xilinx/xcu_cells_xtra.v
+++ b/techlibs/xilinx/xcu_cells_xtra.v
@@ -7948,8 +7948,10 @@ module SYSMONE1 (...);
     output [4:0] MUXADDR;
     output OT;
     input CONVST;
+    (* invertible_pin = "IS_CONVSTCLK_INVERTED" *)
     input CONVSTCLK;
     input [7:0] DADDR;
+    (* invertible_pin = "IS_DCLK_INVERTED" *)
     input DCLK;
     input DEN;
     input [15:0] DI;
@@ -8058,8 +8060,10 @@ module SYSMONE4 (...);
     output OT;
     output SMBALERT_TS;
     input CONVST;
+    (* invertible_pin = "IS_CONVSTCLK_INVERTED" *)
     input CONVSTCLK;
     input [7:0] DADDR;
+    (* invertible_pin = "IS_DCLK_INVERTED" *)
     input DCLK;
     input DEN;
     input [15:0] DI;
@@ -8134,11 +8138,13 @@ module DSP48E2 (...);
     output [7:0] XOROUT;
     input [29:0] A;
     input [29:0] ACIN;
+    (* invertible_pin = "IS_ALUMODE_INVERTED" *)
     input [3:0] ALUMODE;
     input [17:0] B;
     input [17:0] BCIN;
     input [47:0] C;
     input CARRYCASCIN;
+    (* invertible_pin = "IS_CARRYIN_INVERTED" *)
     input CARRYIN;
     input [2:0] CARRYINSEL;
     input CEA1;
@@ -8155,21 +8161,34 @@ module DSP48E2 (...);
     input CEM;
     input CEP;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
     input [26:0] D;
+    (* invertible_pin = "IS_INMODE_INVERTED" *)
     input [4:0] INMODE;
     input MULTSIGNIN;
+    (* invertible_pin = "IS_OPMODE_INVERTED" *)
     input [8:0] OPMODE;
     input [47:0] PCIN;
+    (* invertible_pin = "IS_RSTA_INVERTED" *)
     input RSTA;
+    (* invertible_pin = "IS_RSTALLCARRYIN_INVERTED" *)
     input RSTALLCARRYIN;
+    (* invertible_pin = "IS_RSTALUMODE_INVERTED" *)
     input RSTALUMODE;
+    (* invertible_pin = "IS_RSTB_INVERTED" *)
     input RSTB;
+    (* invertible_pin = "IS_RSTC_INVERTED" *)
     input RSTC;
+    (* invertible_pin = "IS_RSTCTRL_INVERTED" *)
     input RSTCTRL;
+    (* invertible_pin = "IS_RSTD_INVERTED" *)
     input RSTD;
+    (* invertible_pin = "IS_RSTINMODE_INVERTED" *)
     input RSTINMODE;
+    (* invertible_pin = "IS_RSTM_INVERTED" *)
     input RSTM;
+    (* invertible_pin = "IS_RSTP_INVERTED" *)
     input RSTP;
 endmodule
 
@@ -8221,14 +8240,20 @@ module FIFO18E2 (...);
     input [31:0] DIN;
     input [3:0] DINP;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_RDCLK_INVERTED" *)
     input RDCLK;
+    (* invertible_pin = "IS_RDEN_INVERTED" *)
     input RDEN;
     input REGCE;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
+    (* invertible_pin = "IS_RSTREG_INVERTED" *)
     input RSTREG;
     input SLEEP;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WRCLK_INVERTED" *)
     input WRCLK;
+    (* invertible_pin = "IS_WREN_INVERTED" *)
     input WREN;
 endmodule
 
@@ -8288,14 +8313,20 @@ module FIFO36E2 (...);
     input INJECTDBITERR;
     input INJECTSBITERR;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_RDCLK_INVERTED" *)
     input RDCLK;
+    (* invertible_pin = "IS_RDEN_INVERTED" *)
     input RDEN;
     input REGCE;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
+    (* invertible_pin = "IS_RSTREG_INVERTED" *)
     input RSTREG;
     input SLEEP;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WRCLK_INVERTED" *)
     input WRCLK;
+    (* invertible_pin = "IS_WREN_INVERTED" *)
     input WREN;
 endmodule
 
@@ -8431,20 +8462,28 @@ module RAMB18E2 (...);
     input CASOREGIMUXEN_A;
     input CASOREGIMUXEN_B;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLKARDCLK_INVERTED" *)
     input CLKARDCLK;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLKBWRCLK_INVERTED" *)
     input CLKBWRCLK;
     input [15:0] DINADIN;
     input [15:0] DINBDIN;
     input [1:0] DINPADINP;
     input [1:0] DINPBDINP;
+    (* invertible_pin = "IS_ENARDEN_INVERTED" *)
     input ENARDEN;
+    (* invertible_pin = "IS_ENBWREN_INVERTED" *)
     input ENBWREN;
     input REGCEAREGCE;
     input REGCEB;
+    (* invertible_pin = "IS_RSTRAMARSTRAM_INVERTED" *)
     input RSTRAMARSTRAM;
+    (* invertible_pin = "IS_RSTRAMB_INVERTED" *)
     input RSTRAMB;
+    (* invertible_pin = "IS_RSTREGARSTREG_INVERTED" *)
     input RSTREGARSTREG;
+    (* invertible_pin = "IS_RSTREGB_INVERTED" *)
     input RSTREGB;
     input SLEEP;
     input [1:0] WEA;
@@ -8666,23 +8705,31 @@ module RAMB36E2 (...);
     input CASOREGIMUXEN_A;
     input CASOREGIMUXEN_B;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLKARDCLK_INVERTED" *)
     input CLKARDCLK;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLKBWRCLK_INVERTED" *)
     input CLKBWRCLK;
     input [31:0] DINADIN;
     input [31:0] DINBDIN;
     input [3:0] DINPADINP;
     input [3:0] DINPBDINP;
     input ECCPIPECE;
+    (* invertible_pin = "IS_ENARDEN_INVERTED" *)
     input ENARDEN;
+    (* invertible_pin = "IS_ENBWREN_INVERTED" *)
     input ENBWREN;
     input INJECTDBITERR;
     input INJECTSBITERR;
     input REGCEAREGCE;
     input REGCEB;
+    (* invertible_pin = "IS_RSTRAMARSTRAM_INVERTED" *)
     input RSTRAMARSTRAM;
+    (* invertible_pin = "IS_RSTRAMB_INVERTED" *)
     input RSTRAMB;
+    (* invertible_pin = "IS_RSTREGARSTREG_INVERTED" *)
     input RSTREGARSTREG;
+    (* invertible_pin = "IS_RSTREGB_INVERTED" *)
     input RSTREGB;
     input SLEEP;
     input [3:0] WEA;
@@ -8777,10 +8824,13 @@ module URAM288 (...);
     input CAS_IN_SBITERR_A;
     input CAS_IN_SBITERR_B;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
     input [71:0] DIN_A;
     input [71:0] DIN_B;
+    (* invertible_pin = "IS_EN_A_INVERTED" *)
     input EN_A;
+    (* invertible_pin = "IS_EN_B_INVERTED" *)
     input EN_B;
     input INJECT_DBITERR_A;
     input INJECT_DBITERR_B;
@@ -8790,9 +8840,13 @@ module URAM288 (...);
     input OREG_CE_B;
     input OREG_ECC_CE_A;
     input OREG_ECC_CE_B;
+    (* invertible_pin = "IS_RDB_WR_A_INVERTED" *)
     input RDB_WR_A;
+    (* invertible_pin = "IS_RDB_WR_B_INVERTED" *)
     input RDB_WR_B;
+    (* invertible_pin = "IS_RST_A_INVERTED" *)
     input RST_A;
+    (* invertible_pin = "IS_RST_B_INVERTED" *)
     input RST_B;
     input SLEEP;
 endmodule
@@ -8835,10 +8889,13 @@ module URAM288_BASE (...);
     input [8:0] BWE_A;
     input [8:0] BWE_B;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
     input [71:0] DIN_A;
     input [71:0] DIN_B;
+    (* invertible_pin = "IS_EN_A_INVERTED" *)
     input EN_A;
+    (* invertible_pin = "IS_EN_B_INVERTED" *)
     input EN_B;
     input INJECT_DBITERR_A;
     input INJECT_DBITERR_B;
@@ -8848,9 +8905,13 @@ module URAM288_BASE (...);
     input OREG_CE_B;
     input OREG_ECC_CE_A;
     input OREG_ECC_CE_B;
+    (* invertible_pin = "IS_RDB_WR_A_INVERTED" *)
     input RDB_WR_A;
+    (* invertible_pin = "IS_RDB_WR_B_INVERTED" *)
     input RDB_WR_B;
+    (* invertible_pin = "IS_RST_A_INVERTED" *)
     input RST_A;
+    (* invertible_pin = "IS_RST_B_INVERTED" *)
     input RST_B;
     input SLEEP;
 endmodule
@@ -8868,6 +8929,7 @@ module RAM128X1S (...);
     input A6;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -8881,6 +8943,7 @@ module RAM256X1D (...);
     input D;
     input [7:0] DPRA;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -8892,6 +8955,7 @@ module RAM256X1S (...);
     input [7:0] A;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -8915,6 +8979,7 @@ module RAM32M (...);
     input [1:0] DIC;
     input [1:0] DID;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -8954,6 +9019,7 @@ module RAM32M16 (...);
     input [1:0] DIG;
     input [1:0] DIH;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -8969,6 +9035,7 @@ module RAM32X1S (...);
     input A4;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -8980,6 +9047,7 @@ module RAM512X1S (...);
     input [8:0] A;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -9003,6 +9071,7 @@ module RAM64M (...);
     input DIC;
     input DID;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -9042,6 +9111,7 @@ module RAM64M8 (...);
     input DIG;
     input DIH;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -9058,6 +9128,7 @@ module RAM64X1S (...);
     input A5;
     input D;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_WCLK_INVERTED" *)
     input WCLK;
     input WE;
 endmodule
@@ -9066,6 +9137,7 @@ module AND2B1L (...);
     parameter [0:0] IS_SRI_INVERTED = 1'b0;
     output O;
     input DI;
+    (* invertible_pin = "IS_SRI_INVERTED" *)
     input SRI;
 endmodule
 
@@ -9093,6 +9165,7 @@ module CFGLUT5 (...);
     input CDI;
     input CE;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
 endmodule
 
@@ -9107,6 +9180,7 @@ module OR2L (...);
     parameter [0:0] IS_SRI_INVERTED = 1'b0;
     output O;
     input DI;
+    (* invertible_pin = "IS_SRI_INVERTED" *)
     input SRI;
 endmodule
 
@@ -9141,7 +9215,9 @@ module BUFGCE (...);
     parameter [0:0] IS_I_INVERTED = 1'b0;
     (* clkbuf_driver *)
     output O;
+    (* invertible_pin = "IS_CE_INVERTED" *)
     input CE;
+    (* invertible_pin = "IS_I_INVERTED" *)
     input I;
 endmodule
 
@@ -9159,8 +9235,11 @@ module BUFGCE_DIV (...);
     parameter [0:0] IS_I_INVERTED = 1'b0;
     (* clkbuf_driver *)
     output O;
+    (* invertible_pin = "IS_CE_INVERTED" *)
     input CE;
+    (* invertible_pin = "IS_CLR_INVERTED" *)
     input CLR;
+    (* invertible_pin = "IS_I_INVERTED" *)
     input I;
 endmodule
 
@@ -9270,9 +9349,13 @@ module MMCME3_ADV (...);
     output LOCKED;
     output PSDONE;
     input CDDCREQ;
+    (* invertible_pin = "IS_CLKFBIN_INVERTED" *)
     input CLKFBIN;
+    (* invertible_pin = "IS_CLKIN1_INVERTED" *)
     input CLKIN1;
+    (* invertible_pin = "IS_CLKIN2_INVERTED" *)
     input CLKIN2;
+    (* invertible_pin = "IS_CLKINSEL_INVERTED" *)
     input CLKINSEL;
     input [6:0] DADDR;
     input DCLK;
@@ -9280,9 +9363,13 @@ module MMCME3_ADV (...);
     input [15:0] DI;
     input DWE;
     input PSCLK;
+    (* invertible_pin = "IS_PSEN_INVERTED" *)
     input PSEN;
+    (* invertible_pin = "IS_PSINCDEC_INVERTED" *)
     input PSINCDEC;
+    (* invertible_pin = "IS_PWRDWN_INVERTED" *)
     input PWRDWN;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
 endmodule
 
@@ -9334,9 +9421,13 @@ module MMCME3_BASE (...);
     output CLKOUT5;
     output CLKOUT6;
     output LOCKED;
+    (* invertible_pin = "IS_CLKFBIN_INVERTED" *)
     input CLKFBIN;
+    (* invertible_pin = "IS_CLKIN1_INVERTED" *)
     input CLKIN1;
+    (* invertible_pin = "IS_PWRDWN_INVERTED" *)
     input PWRDWN;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
 endmodule
 
@@ -9420,9 +9511,13 @@ module MMCME4_ADV (...);
     output LOCKED;
     output PSDONE;
     input CDDCREQ;
+    (* invertible_pin = "IS_CLKFBIN_INVERTED" *)
     input CLKFBIN;
+    (* invertible_pin = "IS_CLKIN1_INVERTED" *)
     input CLKIN1;
+    (* invertible_pin = "IS_CLKIN2_INVERTED" *)
     input CLKIN2;
+    (* invertible_pin = "IS_CLKINSEL_INVERTED" *)
     input CLKINSEL;
     input [6:0] DADDR;
     input DCLK;
@@ -9430,9 +9525,13 @@ module MMCME4_ADV (...);
     input [15:0] DI;
     input DWE;
     input PSCLK;
+    (* invertible_pin = "IS_PSEN_INVERTED" *)
     input PSEN;
+    (* invertible_pin = "IS_PSINCDEC_INVERTED" *)
     input PSINCDEC;
+    (* invertible_pin = "IS_PWRDWN_INVERTED" *)
     input PWRDWN;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
 endmodule
 
@@ -9484,9 +9583,13 @@ module MMCME4_BASE (...);
     output CLKOUT5;
     output CLKOUT6;
     output LOCKED;
+    (* invertible_pin = "IS_CLKFBIN_INVERTED" *)
     input CLKFBIN;
+    (* invertible_pin = "IS_CLKIN1_INVERTED" *)
     input CLKIN1;
+    (* invertible_pin = "IS_PWRDWN_INVERTED" *)
     input PWRDWN;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
 endmodule
 
@@ -9525,7 +9628,9 @@ module PLLE3_ADV (...);
     output [15:0] DO;
     output DRDY;
     output LOCKED;
+    (* invertible_pin = "IS_CLKFBIN_INVERTED" *)
     input CLKFBIN;
+    (* invertible_pin = "IS_CLKIN_INVERTED" *)
     input CLKIN;
     input CLKOUTPHYEN;
     input [6:0] DADDR;
@@ -9533,7 +9638,9 @@ module PLLE3_ADV (...);
     input DEN;
     input [15:0] DI;
     input DWE;
+    (* invertible_pin = "IS_PWRDWN_INVERTED" *)
     input PWRDWN;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
 endmodule
 
@@ -9562,10 +9669,14 @@ module PLLE3_BASE (...);
     output CLKOUT1B;
     output CLKOUTPHY;
     output LOCKED;
+    (* invertible_pin = "IS_CLKFBIN_INVERTED" *)
     input CLKFBIN;
+    (* invertible_pin = "IS_CLKIN_INVERTED" *)
     input CLKIN;
     input CLKOUTPHYEN;
+    (* invertible_pin = "IS_PWRDWN_INVERTED" *)
     input PWRDWN;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
 endmodule
 
@@ -9604,7 +9715,9 @@ module PLLE4_ADV (...);
     output [15:0] DO;
     output DRDY;
     output LOCKED;
+    (* invertible_pin = "IS_CLKFBIN_INVERTED" *)
     input CLKFBIN;
+    (* invertible_pin = "IS_CLKIN_INVERTED" *)
     input CLKIN;
     input CLKOUTPHYEN;
     input [6:0] DADDR;
@@ -9612,7 +9725,9 @@ module PLLE4_ADV (...);
     input DEN;
     input [15:0] DI;
     input DWE;
+    (* invertible_pin = "IS_PWRDWN_INVERTED" *)
     input PWRDWN;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
 endmodule
 
@@ -9641,10 +9756,14 @@ module PLLE4_BASE (...);
     output CLKOUT1B;
     output CLKOUTPHY;
     output LOCKED;
+    (* invertible_pin = "IS_CLKFBIN_INVERTED" *)
     input CLKFBIN;
+    (* invertible_pin = "IS_CLKIN_INVERTED" *)
     input CLKIN;
     input CLKOUTPHYEN;
+    (* invertible_pin = "IS_PWRDWN_INVERTED" *)
     input PWRDWN;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
 endmodule
 
@@ -10035,6 +10154,7 @@ module IDELAYE3 (...);
     input CASC_RETURN;
     input CE;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
     input [8:0] CNTVALUEIN;
     input DATAIN;
@@ -10042,6 +10162,7 @@ module IDELAYE3 (...);
     input IDATAIN;
     input INC;
     input LOAD;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
 endmodule
 
@@ -10249,15 +10370,18 @@ module ISERDESE3 (...);
     output INTERNAL_DIVCLK;
     output [7:0] Q;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
     (* clkbuf_sink *)
     input CLKDIV;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLK_B_INVERTED" *)
     input CLK_B;
     input D;
     (* clkbuf_sink *)
     input FIFO_RD_CLK;
     input FIFO_RD_EN;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
 endmodule
 
@@ -10330,12 +10454,14 @@ module ODELAYE3 (...);
     input CASC_RETURN;
     input CE;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
     input [8:0] CNTVALUEIN;
     input EN_VTC;
     input INC;
     input LOAD;
     input ODATAIN;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
 endmodule
 
@@ -10353,10 +10479,13 @@ module OSERDESE3 (...);
     output OQ;
     output T_OUT;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLKDIV_INVERTED" *)
     input CLKDIV;
     input [7:0] D;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
     input T;
 endmodule
@@ -10408,7 +10537,9 @@ module RX_BITSLICE (...);
     output [39:0] TX_BIT_CTRL_OUT;
     input CE;
     input CE_EXT;
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
+    (* invertible_pin = "IS_CLK_EXT_INVERTED" *)
     input CLK_EXT;
     input [8:0] CNTVALUEIN;
     input [8:0] CNTVALUEIN_EXT;
@@ -10421,8 +10552,11 @@ module RX_BITSLICE (...);
     input INC_EXT;
     input LOAD;
     input LOAD_EXT;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
+    (* invertible_pin = "IS_RST_DLY_INVERTED" *)
     input RST_DLY;
+    (* invertible_pin = "IS_RST_DLY_EXT_INVERTED" *)
     input RST_DLY_EXT;
     input [39:0] RX_BIT_CTRL_IN;
     input [39:0] TX_BIT_CTRL_IN;
@@ -10472,23 +10606,29 @@ module RXTX_BITSLICE (...);
     input FIFO_RD_EN;
     input [39:0] RX_BIT_CTRL_IN;
     input RX_CE;
+    (* invertible_pin = "IS_RX_CLK_INVERTED" *)
     input RX_CLK;
     input [8:0] RX_CNTVALUEIN;
     input RX_EN_VTC;
     input RX_INC;
     input RX_LOAD;
+    (* invertible_pin = "IS_RX_RST_INVERTED" *)
     input RX_RST;
+    (* invertible_pin = "IS_RX_RST_DLY_INVERTED" *)
     input RX_RST_DLY;
     input T;
     input TBYTE_IN;
     input [39:0] TX_BIT_CTRL_IN;
     input TX_CE;
+    (* invertible_pin = "IS_TX_CLK_INVERTED" *)
     input TX_CLK;
     input [8:0] TX_CNTVALUEIN;
     input TX_EN_VTC;
     input TX_INC;
     input TX_LOAD;
+    (* invertible_pin = "IS_TX_RST_INVERTED" *)
     input TX_RST;
+    (* invertible_pin = "IS_TX_RST_DLY_INVERTED" *)
     input TX_RST_DLY;
 endmodule
 
@@ -10515,13 +10655,16 @@ module TX_BITSLICE (...);
     output [39:0] TX_BIT_CTRL_OUT;
     output T_OUT;
     input CE;
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
     input [8:0] CNTVALUEIN;
     input [7:0] D;
     input EN_VTC;
     input INC;
     input LOAD;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
+    (* invertible_pin = "IS_RST_DLY_INVERTED" *)
     input RST_DLY;
     input [39:0] RX_BIT_CTRL_IN;
     input T;
@@ -10549,12 +10692,15 @@ module TX_BITSLICE_TRI (...);
     output TRI_OUT;
     input [39:0] BIT_CTRL_IN;
     input CE;
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
     input [8:0] CNTVALUEIN;
     input EN_VTC;
     input INC;
     input LOAD;
+    (* invertible_pin = "IS_RST_INVERTED" *)
     input RST;
+    (* invertible_pin = "IS_RST_DLY_INVERTED" *)
     input RST_DLY;
 endmodule
 
@@ -10564,6 +10710,7 @@ module HARD_SYNC (...);
     parameter integer LATENCY = 2;
     output DOUT;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CLK_INVERTED" *)
     input CLK;
     input DIN;
 endmodule
@@ -10575,8 +10722,10 @@ module IDDRE1 (...);
     output Q1;
     output Q2;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_C_INVERTED" *)
     input C;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_CB_INVERTED" *)
     input CB;
     input D;
     input R;
@@ -10589,8 +10738,10 @@ module LDCE (...);
     parameter MSGON = "TRUE";
     parameter XON = "TRUE";
     output Q;
+    (* invertible_pin = "IS_CLR_INVERTED" *)
     input CLR;
     input D;
+    (* invertible_pin = "IS_G_INVERTED" *)
     input G;
     input GE;
 endmodule
@@ -10603,8 +10754,10 @@ module LDPE (...);
     parameter XON = "TRUE";
     output Q;
     input D;
+    (* invertible_pin = "IS_G_INVERTED" *)
     input G;
     input GE;
+    (* invertible_pin = "IS_PRE_INVERTED" *)
     input PRE;
 endmodule
 
@@ -10615,8 +10768,11 @@ module ODDRE1 (...);
     parameter [0:0] SRVAL = 1'b0;
     output Q;
     (* clkbuf_sink *)
+    (* invertible_pin = "IS_C_INVERTED" *)
     input C;
+    (* invertible_pin = "IS_D1_INVERTED" *)
     input D1;
+    (* invertible_pin = "IS_D2_INVERTED" *)
     input D2;
     input SR;
 endmodule

From b76fac3ac3a815568827a03b201f386b2577e010 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Thu, 19 Sep 2019 19:26:09 +0200
Subject: [PATCH 4/4] Add techmap_autopurge attribute, fixes #1381

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 passes/techmap/techmap.cc | 54 +++++++++++++++++++++++++++++++++++----
 1 file changed, 49 insertions(+), 5 deletions(-)

diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index 51a65aea6..cf40b2f17 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -206,10 +206,27 @@ struct TechmapWorker
 
 		std::map<RTLIL::IdString, RTLIL::IdString> positional_ports;
 		dict<Wire*, IdString> temp_renamed_wires;
+		pool<SigBit> autopurge_tpl_bits;
 
-		for (auto &it : tpl->wires_) {
+		for (auto &it : tpl->wires_)
+		{
 			if (it.second->port_id > 0)
-				positional_ports[stringf("$%d", it.second->port_id)] = it.first;
+			{
+				IdString posportname = stringf("$%d", it.second->port_id);
+				positional_ports[posportname] = it.first;
+
+				if (!flatten_mode && it.second->get_bool_attribute(ID(techmap_autopurge)) &&
+						(!cell->hasPort(it.second->name) || !GetSize(cell->getPort(it.second->name))) &&
+						(!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname))))
+				{
+					if (sigmaps.count(tpl) == 0)
+						sigmaps[tpl].set(tpl);
+
+					for (auto bit : sigmaps.at(tpl)(it.second))
+						if (bit.wire != nullptr)
+							autopurge_tpl_bits.insert(it.second);
+				}
+			}
 			IdString w_name = it.second->name;
 			apply_prefix(cell->name, w_name);
 			RTLIL::Wire *w = module->wire(w_name);
@@ -232,6 +249,8 @@ struct TechmapWorker
 				w->port_input = false;
 				w->port_output = false;
 				w->port_id = 0;
+				if (!flatten_mode)
+					w->attributes.erase(ID(techmap_autopurge));
 				if (it.second->get_bool_attribute(ID(_techmap_special_)))
 					w->attributes.clear();
 				if (w->attributes.count(ID(src)))
@@ -362,11 +381,31 @@ struct TechmapWorker
 			if (!flatten_mode && c->type.begins_with("\\$"))
 				c->type = c->type.substr(1);
 
-			for (auto &it2 : c->connections_) {
-				apply_prefix(cell->name, it2.second, module);
-				port_signal_map.apply(it2.second);
+			vector<IdString> autopurge_ports;
+
+			for (auto &it2 : c->connections_)
+			{
+				bool autopurge = false;
+				if (!autopurge_tpl_bits.empty()) {
+					autopurge = GetSize(it2.second) != 0;
+					for (auto &bit : sigmaps.at(tpl)(it2.second))
+						if (!autopurge_tpl_bits.count(bit)) {
+							autopurge = false;
+							break;
+						}
+				}
+
+				if (autopurge) {
+					autopurge_ports.push_back(it2.first);
+				} else {
+					apply_prefix(cell->name, it2.second, module);
+					port_signal_map.apply(it2.second);
+				}
 			}
 
+			for (auto &it2 : autopurge_ports)
+				c->unsetPort(it2);
+
 			if (c->type.in(ID($memrd), ID($memwr), ID($meminit))) {
 				IdString memid = c->getParam(ID(MEMID)).decode_string();
 				log_assert(memory_renames.count(memid) != 0);
@@ -1064,6 +1103,11 @@ struct TechmapPass : public Pass {
 		log("will create a wrapper for the cell and then run the command string that the\n");
 		log("attribute is set to on the wrapper module.\n");
 		log("\n");
+		log("When a port on a module in the map file has the 'techmap_autopurge' attribute\n");
+		log("set, and that port is not connected in the instantiation that is mapped, then\n");
+		log("then a cell port connected only to such wires will be omitted in the mapped\n");
+		log("version of the circuit.\n");
+		log("\n");
 		log("All wires in the modules from the map file matching the pattern _TECHMAP_*\n");
 		log("or *._TECHMAP_* are special wires that are used to pass instructions from\n");
 		log("the mapping module to the techmap command. At the moment the following special\n");