Modify java for convient integration.

Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
diff --git a/dump_bram.java b/dump_bram.java
index 381a4de..c2fbaeb 100644
--- a/dump_bram.java
+++ b/dump_bram.java
@@ -12,13 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package dev.fpga.rapidwright;
-
 import com.xilinx.rapidwright.design.*;
 import com.xilinx.rapidwright.design.tools.LUTTools;
 import com.xilinx.rapidwright.device.*;
 import com.xilinx.rapidwright.edif.*;
-import jnr.ffi.annotations.In;
 import org.json.Property;
 
 import java.io.File;
@@ -44,291 +41,285 @@
     }
 
     public static void main(String[] args) throws IOException {
-
-        File folder = new File("specimen_bram");
-        File[] listOfFiles = folder.listFiles();
-        for (File f : listOfFiles) {
-            if (f.getName().endsWith(".dcp")) {
-                Design des = Design.readCheckpoint(f.getAbsolutePath());
-                HashMap<String, ArrayList<String>> pips_by_tile = new HashMap<>();
-                HashMap<String, ArrayList<String>> sitefeatures_by_tile = new HashMap<>();
-                for (Net n : des.getNets()) {
-                    for (PIP p : n.getPIPs()) {
-                        String tile = p.getTile().getName() + ":" + p.getTile().getTileTypeEnum().toString();
-                        if (p.getTile().getTileTypeEnum() == TileTypeEnum.BRAM)
-                            continue;
-                        if (!pips_by_tile.containsKey(tile))
-                            pips_by_tile.put(tile, new ArrayList<>());
-                        pips_by_tile.get(tile).add("PIP." + p.getEndWireName() + "." + p.getStartWireName());
-                    }
+        for (String f : args) {
+            Design des = Design.readCheckpoint(f);
+            HashMap<String, ArrayList<String>> pips_by_tile = new HashMap<>();
+            HashMap<String, ArrayList<String>> sitefeatures_by_tile = new HashMap<>();
+            for (Net n : des.getNets()) {
+                for (PIP p : n.getPIPs()) {
+                    String tile = p.getTile().getName() + ":" + p.getTile().getTileTypeEnum().toString();
+                    if (p.getTile().getTileTypeEnum() == TileTypeEnum.BRAM)
+                        continue;
+                    if (!pips_by_tile.containsKey(tile))
+                        pips_by_tile.put(tile, new ArrayList<>());
+                    pips_by_tile.get(tile).add("PIP." + p.getEndWireName() + "." + p.getStartWireName());
                 }
-                for (SiteInst si : des.getSiteInsts()) {
-                    String tile = si.getTile().getName() + ":" + si.getTile().getTileTypeEnum().toString();
-                    if (!sitefeatures_by_tile.containsKey(tile))
-                        sitefeatures_by_tile.put(tile, new ArrayList<>());
-                    ArrayList<String> tfeat = sitefeatures_by_tile.get(tile);
-                   if (si.getSiteTypeEnum() == SiteTypeEnum.RAMB180 || si.getSiteTypeEnum() == SiteTypeEnum.RAMB181 || si.getSiteTypeEnum() == SiteTypeEnum.RAMB36) {
-                        for (BEL b : si.getBELs()) {
-                            String belName = b.getName();
-                            Cell c = si.getCell(b);
-                            if (c == null || c.getType() == null)
-                                continue;
-                            if ((si.getSiteTypeEnum() == SiteTypeEnum.RAMB36 && !c.getType().equals("RAMB36E2")) ||
-                                    ((si.getSiteTypeEnum() == SiteTypeEnum.RAMB180 || si.getSiteTypeEnum() == SiteTypeEnum.RAMB181) && !c.getType().equals("RAMB18E2")))
-                                continue;
-                            int prim_width = si.getSiteTypeEnum() == SiteTypeEnum.RAMB36 ? 36 : 18;
-                            tfeat.add("BRAM.IN_USE");
-                            tfeat.add(belName + ".IN_USE");
-                            boolean have_ecc = false;
+            }
+            for (SiteInst si : des.getSiteInsts()) {
+                String tile = si.getTile().getName() + ":" + si.getTile().getTileTypeEnum().toString();
+                if (!sitefeatures_by_tile.containsKey(tile))
+                    sitefeatures_by_tile.put(tile, new ArrayList<>());
+                ArrayList<String> tfeat = sitefeatures_by_tile.get(tile);
+                if (si.getSiteTypeEnum() == SiteTypeEnum.RAMB180 || si.getSiteTypeEnum() == SiteTypeEnum.RAMB181 || si.getSiteTypeEnum() == SiteTypeEnum.RAMB36) {
+                    for (BEL b : si.getBELs()) {
+                        String belName = b.getName();
+                        Cell c = si.getCell(b);
+                        if (c == null || c.getType() == null)
+                            continue;
+                        if ((si.getSiteTypeEnum() == SiteTypeEnum.RAMB36 && !c.getType().equals("RAMB36E2")) ||
+                                ((si.getSiteTypeEnum() == SiteTypeEnum.RAMB180 || si.getSiteTypeEnum() == SiteTypeEnum.RAMB181) && !c.getType().equals("RAMB18E2")))
+                            continue;
+                        int prim_width = si.getSiteTypeEnum() == SiteTypeEnum.RAMB36 ? 36 : 18;
+                        tfeat.add("BRAM.IN_USE");
+                        tfeat.add(belName + ".IN_USE");
+                        boolean have_ecc = false;
 
-                            boolean is_sdp = false;
-                            if (c.getProperty("READ_WIDTH_A") != null && Integer.parseInt(c.getProperty("READ_WIDTH_A").getValue()) > prim_width)
-                                is_sdp = true;
-                            if (c.getProperty("WRITE_WIDTH_B") != null && Integer.parseInt(c.getProperty("WRITE_WIDTH_B").getValue()) > prim_width)
-                                is_sdp = true;
+                        boolean is_sdp = false;
+                        if (c.getProperty("READ_WIDTH_A") != null && Integer.parseInt(c.getProperty("READ_WIDTH_A").getValue()) > prim_width)
+                            is_sdp = true;
+                        if (c.getProperty("WRITE_WIDTH_B") != null && Integer.parseInt(c.getProperty("WRITE_WIDTH_B").getValue()) > prim_width)
+                            is_sdp = true;
 
-                            String[] enum_props = {
-                                    "CLOCK_DOMAINS",
-                                    "DOA_REG", "DOB_REG",
-                                    "READ_WIDTH_A", "READ_WIDTH_B", "WRITE_WIDTH_A", "WRITE_WIDTH_B",
-                                    "WRITE_MODE_A", "WRITE_MODE_B",
-                                    "ENADDRENA", "ENADDRENB", "RDADDRCHANGEA", "RDADDRCHANGEB",
-                                    "RSTREG_PRIORITY_A", "RSTREG_PRIORITY_B",
-                                    "SLEEP_ASYNC", "EN_ECC_PIPE", "EN_ECC_READ", "EN_ECC_WRITE",
-                                    "CASCADE_ORDER_A", "CASCADE_ORDER_B"};
+                        String[] enum_props = {
+                                "CLOCK_DOMAINS",
+                                "DOA_REG", "DOB_REG",
+                                "READ_WIDTH_A", "READ_WIDTH_B", "WRITE_WIDTH_A", "WRITE_WIDTH_B",
+                                "WRITE_MODE_A", "WRITE_MODE_B",
+                                "ENADDRENA", "ENADDRENB", "RDADDRCHANGEA", "RDADDRCHANGEB",
+                                "RSTREG_PRIORITY_A", "RSTREG_PRIORITY_B",
+                                "SLEEP_ASYNC", "EN_ECC_PIPE", "EN_ECC_READ", "EN_ECC_WRITE",
+                                "CASCADE_ORDER_A", "CASCADE_ORDER_B"};
+                        for (String p : enum_props) {
+                            EDIFPropertyValue ep = c.getProperty(p);
+                            if (ep == null)
+                                continue;
+                            String v = ep.getValue();
+                            int base_pos = v.indexOf("'b");
+                            if (base_pos != -1)
+                                v = v.substring(base_pos + 2);
+                            if (p.startsWith("RSTREG_") && is_sdp)
+                                continue;
+                            tfeat.add(belName + "." + p + "." + v);
+                            if (p.contains("EN_ECC") && v.equals("TRUE"))
+                                have_ecc = true;
+                        }
+
+                        var all_props = c.getProperties();
+                        for (var e : all_props.entrySet()) {
+                            String name = e.getKey().getName();
+                            if (name.startsWith("IS_") && name.endsWith("_INVERTED")) {
+                                String pinname = name.substring(3, name.length() - 9);
+                                String v = e.getValue().getValue();
+                                int base_pos = v.indexOf("'b");
+                                if (base_pos != -1)
+                                    v = v.substring(base_pos + 2);
+                                tfeat.add(belName + "." + pinname + "INV." + v);
+                            }
+                        }
+
+                        String[] word_props = {"INIT_A", "INIT_B", "SRVAL_A", "SRVAL_B"};
+                        for (String p : word_props) {
+                            EDIFPropertyValue width = c.getProperty("READ_WIDTH_" + p.substring(p.length() - 1));
+                            if (width == null || !width.getValue().equals(Integer.toString(prim_width)) || have_ecc)
+                                continue;
+                            if (c.getProperty(p) != null) {
+                                long lval = LUTTools.getInitValue(c.getProperty(p).getValue());
+                                for (int i = 0; i < prim_width; i++) {
+                                    if ((lval & (1L << i)) != 0)
+                                        tfeat.add(belName + "." + p + "[" + i + "]");
+                                }
+                            }
+                        }
+                        for (EDIFPortInst epi : c.getEDIFCellInst().getPortInsts()) {
+                            if (epi.getName().startsWith("DOUT") && epi.getNet() != null)
+                                tfeat.add(belName + "." + epi.getName() + ".USED");
+                        }
+                    }
+                } else if (si.getSiteTypeEnum() == SiteTypeEnum.DSP48E2) {
+                    for (Cell c : si.getCells()) {
+                        if (!c.getName().contains("/"))
+                            continue;
+                        EDIFCellInst eci = des.getTopEDIFCell().getCellInst(c.getName().split("/")[0]);
+                        if (eci == null)
+                            continue;
+                        if (eci.getCellType().getName() != null && eci.getCellType().getName().equals("DSP48E2")) {
+                            String name = site_index_in_tile(si.getTile(), si.getSite());
+                            tfeat.add("DSP.IN_USE");
+                            tfeat.add(name + ".IN_USE");
+                            boolean have_patdet = false;
+                            if (eci.getProperty("USE_PATTERN_DETECT") != null && eci.getProperty("USE_PATTERN_DETECT").getValue().equals("PATDET"))
+                                have_patdet = true;
+                            boolean have_xor = false;
+                            if (eci.getProperty("USE_WIDEXOR") != null && eci.getProperty("USE_WIDEXOR").getValue().equals("TRUE"))
+                                have_xor = true;
+
+                            String[] enum_props = {"ADREG", "ALUMODEREG", "AMULTSEL", "AREG", "AUTORESET_PATDET", "AUTORESET_PRIORITY",
+                                "BMULTSEL", "BREG", "CARRYINREG", "CARRYINSELREG", "CREG", "DREG", "INMODEREG", "MREG", "OPMODEREG",
+                                    "PREADDINSEL", "PREG", "SEL_MASK", "SEL_PATTERN", "USE_PATTERN_DETECT", "USE_SIMD", "USE_WIDEXOR", "XORSIMD"};
                             for (String p : enum_props) {
-                                EDIFPropertyValue ep = c.getProperty(p);
+                                EDIFPropertyValue ep = eci.getProperty(p);
                                 if (ep == null)
                                     continue;
+                                if (!have_patdet && (p.equals("AUTORESET_PATDET") || p.equals("AUTORESET_PRIORITY") || p.equals("SEL_MASK") || p.equals("SEL_PATTERN")))
+                                    continue;
+                                if (!have_xor && p.equals("XORSIMD"))
+                                    continue;
                                 String v = ep.getValue();
                                 int base_pos = v.indexOf("'b");
                                 if (base_pos != -1)
                                     v = v.substring(base_pos + 2);
-                                if (p.startsWith("RSTREG_") && is_sdp)
-                                    continue;
-                                tfeat.add(belName + "." + p + "." + v);
-                                if (p.contains("EN_ECC") && v.equals("TRUE"))
-                                    have_ecc = true;
+                                tfeat.add(name + "." + p + "." + v);
                             }
 
-                            var all_props = c.getProperties();
+                            var all_props = eci.getProperties();
                             for (var e : all_props.entrySet()) {
-                                String name = e.getKey().getName();
-                                if (name.startsWith("IS_") && name.endsWith("_INVERTED")) {
-                                    String pinname = name.substring(3, name.length() - 9);
+                                String pname = e.getKey().getName();
+                                if (pname.startsWith("IS_") && pname.endsWith("_INVERTED")) {
+                                    String pinname = pname.substring(3, pname.length() - 9);
+                                    int width = 1;
+                                    if (pinname.equals("ALUMODE"))
+                                        width = 4;
+                                    else if (pinname.equals("INMODE"))
+                                        width = 5;
+                                    else if (pinname.equals("OPMODE"))
+                                        width = 9;
+                                    if (pinname.contains("RST") && (eci.getPortInst(pinname).getNet() == null || eci.getPortInst(pinname).getNet().getName().contains("const")))
+                                        continue;
                                     String v = e.getValue().getValue();
-                                    int base_pos = v.indexOf("'b");
-                                    if (base_pos != -1)
-                                        v = v.substring(base_pos + 2);
-                                    tfeat.add(belName + "." + pinname + "INV." + v);
+                                    if (width == 1) {
+                                        int base_pos = v.indexOf("'b");
+                                        if (base_pos != -1)
+                                            v = v.substring(base_pos + 2);
+                                        tfeat.add(name + "." + pinname + "INV." + v);
+                                    } else {
+                                        long lval = LUTTools.getInitValue(v);
+                                        for (int i = 0; i < width; i++) {
+                                            tfeat.add(name + "." + pinname + "INV" + "[" + i + "]." + (((lval & (1L << i)) != 0) ? "1" : "0"));
+                                        }
+                                    }
+
                                 }
                             }
 
-                            String[] word_props = {"INIT_A", "INIT_B", "SRVAL_A", "SRVAL_B"};
-                            for (String p : word_props) {
-                                EDIFPropertyValue width = c.getProperty("READ_WIDTH_" + p.substring(p.length() - 1));
-                                if (width == null || !width.getValue().equals(Integer.toString(prim_width)) || have_ecc)
-                                    continue;
-                                if (c.getProperty(p) != null) {
-                                    long lval = LUTTools.getInitValue(c.getProperty(p).getValue());
-                                    for (int i = 0; i < prim_width; i++) {
-                                        if ((lval & (1L << i)) != 0)
-                                            tfeat.add(belName + "." + p + "[" + i + "]");
+                            if (/*have_patdet*/true) {
+                                String[] word_props = {"MASK", "PATTERN", "RND"};
+                                for (String p : word_props) {
+                                    if (eci.getProperty(p) != null) {
+                                        long lval = LUTTools.getInitValue(eci.getProperty(p).getValue());
+                                        for (int i = 0; i < 48; i++) {
+                                            if ((lval & (1L << i)) != 0 || (p.equals("MASK") && !have_patdet))
+                                                tfeat.add(name + "." + p + "[" + i + "]");
+                                        }
                                     }
                                 }
                             }
-                            for (EDIFPortInst epi : c.getEDIFCellInst().getPortInsts()) {
-                                if (epi.getName().startsWith("DOUT") && epi.getNet() != null)
-                                    tfeat.add(belName + "." + epi.getName() + ".USED");
+                            boolean pins_used = false, d_grounded = true;
+                            for (EDIFPortInst epi : eci.getPortInsts()) {
+                                if (epi.isOutput() && epi.getNet() != null) {
+                                    tfeat.add(name + "." + epi.getName() + ".USED");
+                                }
+                            }
+                            for (SitePinInst spi : si.getSitePinInsts()) {
+                                if (!spi.getName().startsWith("DIN"))
+                                    continue;
+                                if (spi.getNet() != null) {
+                                    pins_used = true;
+                                    if (!spi.getNet().isStaticNet())
+                                        d_grounded = false;
+                                }
+                            }
+                            if (pins_used && d_grounded)
+                                tfeat.add(name + ".D_NOT_USED");
+                            //if (c_grounded)
+                            //    tfeat.add(name + ".C_NOT_USED");
+                            break;
+                        }
+                    }
+
+                } else if (si.getSiteTypeEnum() == SiteTypeEnum.URAM288) {
+                    Cell c = si.getCell("URAM_288K_INST");
+                    if (c == null || c.getType() == null)
+                        continue;
+                    String name = site_index_in_tile(si.getTile(), si.getSite());
+                    tfeat.add("URAM.IN_USE");
+                    tfeat.add(name + ".IN_USE");
+                    String[] enum_props = {"BWE_MODE_A", "BWE_MODE_B", "EN_AUTO_SLEEP_MODE", "EN_ECC_RD_A", "EN_ECC_RD_B",
+                            "EN_ECC_WR_A", "EN_ECC_WR_B", "IREG_PRE_A", "IREG_PRE_B", "OREG_A", "OREG_B", "OREG_ECC_A", "OREG_ECC_B", "REG_CAS_A",
+                            "REG_CAS_B", "RST_MODE_A", "RST_MODE_B", "USE_EXT_CE_A", "USE_EXT_CE_B"};
+                    for (String p : enum_props) {
+                        EDIFPropertyValue ep = c.getProperty(p);
+                        if (ep == null)
+                            continue;
+                        String v = ep.getValue();
+                        int base_pos = v.indexOf("'b");
+                        if (base_pos != -1)
+                            v = v.substring(base_pos + 2);
+                        tfeat.add(name + "." + p + "." + v);
+                    }
+
+                    var all_props = c.getProperties();
+                    for (var e : all_props.entrySet()) {
+                        String prop_name = e.getKey().getName();
+                        if (prop_name.startsWith("IS_") && prop_name.endsWith("_INVERTED")) {
+                            String pinname = prop_name.substring(3, prop_name.length() - 9);
+                            if (c.getLogicalPinMapping(pinname) == null)
+                                continue;
+                            Net n = si.getNetFromSiteWire(c.getSiteWireNameFromLogicalPin(pinname));
+                            if (n == null || n.isStaticNet())
+                                continue;
+                            String v = e.getValue().getValue();
+                            int base_pos = v.indexOf("'b");
+                            if (base_pos != -1)
+                                v = v.substring(base_pos + 2);
+                            tfeat.add(name + "." + pinname + "INV." + v);
+                        }
+                    }
+
+                    String[] word_props = {"SELF_ADDR_A", "SELF_ADDR_B", "SELF_MASK_A", "SELF_MASK_B"};
+                    for (String p : word_props) {
+                        if (c.getProperty(p) != null) {
+                            long lval = LUTTools.getInitValue(c.getProperty(p).getValue());
+                            for (int i = 0; i < 11; i++) {
+                                boolean is_inv = p.contains("_MASK_");
+                                if (((lval >> i) & 0x1) == (is_inv ? 0 : 1))
+                                    tfeat.add(name + "." + p + (is_inv ? "_INV" : "") + "[" + i + "]");
                             }
                         }
-                    } else if (si.getSiteTypeEnum() == SiteTypeEnum.DSP48E2) {
-                       for (Cell c : si.getCells()) {
-                           if (!c.getName().contains("/"))
-                               continue;
-                           EDIFCellInst eci = des.getTopEDIFCell().getCellInst(c.getName().split("/")[0]);
-                           if (eci == null)
-                               continue;
-                           if (eci.getCellType().getName() != null && eci.getCellType().getName().equals("DSP48E2")) {
-                               String name = site_index_in_tile(si.getTile(), si.getSite());
-                               tfeat.add("DSP.IN_USE");
-                               tfeat.add(name + ".IN_USE");
-                               boolean have_patdet = false;
-                               if (eci.getProperty("USE_PATTERN_DETECT") != null && eci.getProperty("USE_PATTERN_DETECT").getValue().equals("PATDET"))
-                                   have_patdet = true;
-                               boolean have_xor = false;
-                               if (eci.getProperty("USE_WIDEXOR") != null && eci.getProperty("USE_WIDEXOR").getValue().equals("TRUE"))
-                                   have_xor = true;
+                    }
+                    EDIFPropertyValue asl = c.getProperty("AUTO_SLEEP_LATENCY");
+                    if (asl != null) {
+                        int a = Integer.parseInt(asl.getValue());
+                        for (int i = 0; i < 4; i++)
+                            if (((a >> i) & 0x1) == 1) {
+                                tfeat.add(name + ".AUTO_SLEEP_LATENCY[" + i + "]");
+                            }
+                    }
 
-                               String[] enum_props = {"ADREG", "ALUMODEREG", "AMULTSEL", "AREG", "AUTORESET_PATDET", "AUTORESET_PRIORITY",
-                                    "BMULTSEL", "BREG", "CARRYINREG", "CARRYINSELREG", "CREG", "DREG", "INMODEREG", "MREG", "OPMODEREG",
-                                       "PREADDINSEL", "PREG", "SEL_MASK", "SEL_PATTERN", "USE_PATTERN_DETECT", "USE_SIMD", "USE_WIDEXOR", "XORSIMD"};
-                               for (String p : enum_props) {
-                                   EDIFPropertyValue ep = eci.getProperty(p);
-                                   if (ep == null)
-                                       continue;
-                                   if (!have_patdet && (p.equals("AUTORESET_PATDET") || p.equals("AUTORESET_PRIORITY") || p.equals("SEL_MASK") || p.equals("SEL_PATTERN")))
-                                       continue;
-                                   if (!have_xor && p.equals("XORSIMD"))
-                                       continue;
-                                   String v = ep.getValue();
-                                   int base_pos = v.indexOf("'b");
-                                   if (base_pos != -1)
-                                       v = v.substring(base_pos + 2);
-                                   tfeat.add(name + "." + p + "." + v);
-                               }
-
-                               var all_props = eci.getProperties();
-                               for (var e : all_props.entrySet()) {
-                                   String pname = e.getKey().getName();
-                                   if (pname.startsWith("IS_") && pname.endsWith("_INVERTED")) {
-                                       String pinname = pname.substring(3, pname.length() - 9);
-                                       int width = 1;
-                                       if (pinname.equals("ALUMODE"))
-                                           width = 4;
-                                       else if (pinname.equals("INMODE"))
-                                           width = 5;
-                                       else if (pinname.equals("OPMODE"))
-                                           width = 9;
-                                       if (pinname.contains("RST") && (eci.getPortInst(pinname).getNet() == null || eci.getPortInst(pinname).getNet().getName().contains("const")))
-                                           continue;
-                                       String v = e.getValue().getValue();
-                                       if (width == 1) {
-                                           int base_pos = v.indexOf("'b");
-                                           if (base_pos != -1)
-                                               v = v.substring(base_pos + 2);
-                                           tfeat.add(name + "." + pinname + "INV." + v);
-                                       } else {
-                                           long lval = LUTTools.getInitValue(v);
-                                           for (int i = 0; i < width; i++) {
-                                               tfeat.add(name + "." + pinname + "INV" + "[" + i + "]." + (((lval & (1L << i)) != 0) ? "1" : "0"));
-                                           }
-                                       }
-
-                                   }
-                               }
-
-                               if (/*have_patdet*/true) {
-                                   String[] word_props = {"MASK", "PATTERN", "RND"};
-                                   for (String p : word_props) {
-                                       if (eci.getProperty(p) != null) {
-                                           long lval = LUTTools.getInitValue(eci.getProperty(p).getValue());
-                                           for (int i = 0; i < 48; i++) {
-                                               if ((lval & (1L << i)) != 0 || (p.equals("MASK") && !have_patdet))
-                                                   tfeat.add(name + "." + p + "[" + i + "]");
-                                           }
-                                       }
-                                   }
-                               }
-                               boolean pins_used = false, d_grounded = true;
-                               for (EDIFPortInst epi : eci.getPortInsts()) {
-                                   if (epi.isOutput() && epi.getNet() != null) {
-                                       tfeat.add(name + "." + epi.getName() + ".USED");
-                                   }
-                               }
-                               for (SitePinInst spi : si.getSitePinInsts()) {
-                                   if (!spi.getName().startsWith("DIN"))
-                                       continue;
-                                   if (spi.getNet() != null) {
-                                       pins_used = true;
-                                       if (!spi.getNet().isStaticNet())
-                                           d_grounded = false;
-                                   }
-                               }
-                               if (pins_used && d_grounded)
-                                   tfeat.add(name + ".D_NOT_USED");
-                               //if (c_grounded)
-                               //    tfeat.add(name + ".C_NOT_USED");
-                               break;
-                           }
-                       }
-
-                   } else if (si.getSiteTypeEnum() == SiteTypeEnum.URAM288) {
-                       Cell c = si.getCell("URAM_288K_INST");
-                       if (c == null || c.getType() == null)
-                           continue;
-                       String name = site_index_in_tile(si.getTile(), si.getSite());
-                       tfeat.add("URAM.IN_USE");
-                       tfeat.add(name + ".IN_USE");
-                       String[] enum_props = {"BWE_MODE_A", "BWE_MODE_B", "EN_AUTO_SLEEP_MODE", "EN_ECC_RD_A", "EN_ECC_RD_B",
-                               "EN_ECC_WR_A", "EN_ECC_WR_B", "IREG_PRE_A", "IREG_PRE_B", "OREG_A", "OREG_B", "OREG_ECC_A", "OREG_ECC_B", "REG_CAS_A",
-                               "REG_CAS_B", "RST_MODE_A", "RST_MODE_B", "USE_EXT_CE_A", "USE_EXT_CE_B"};
-                       for (String p : enum_props) {
-                           EDIFPropertyValue ep = c.getProperty(p);
-                           if (ep == null)
-                               continue;
-                           String v = ep.getValue();
-                           int base_pos = v.indexOf("'b");
-                           if (base_pos != -1)
-                               v = v.substring(base_pos + 2);
-                           tfeat.add(name + "." + p + "." + v);
-                       }
-
-                       var all_props = c.getProperties();
-                       for (var e : all_props.entrySet()) {
-                           String prop_name = e.getKey().getName();
-                           if (prop_name.startsWith("IS_") && prop_name.endsWith("_INVERTED")) {
-                               String pinname = prop_name.substring(3, prop_name.length() - 9);
-                               if (c.getLogicalPinMapping(pinname) == null)
-                                    continue;
-                               Net n = si.getNetFromSiteWire(c.getSiteWireNameFromLogicalPin(pinname));
-                               if (n == null || n.isStaticNet())
-                                   continue;
-                               String v = e.getValue().getValue();
-                               int base_pos = v.indexOf("'b");
-                               if (base_pos != -1)
-                                   v = v.substring(base_pos + 2);
-                               tfeat.add(name + "." + pinname + "INV." + v);
-                           }
-                       }
-
-                       String[] word_props = {"SELF_ADDR_A", "SELF_ADDR_B", "SELF_MASK_A", "SELF_MASK_B"};
-                       for (String p : word_props) {
-                           if (c.getProperty(p) != null) {
-                               long lval = LUTTools.getInitValue(c.getProperty(p).getValue());
-                               for (int i = 0; i < 11; i++) {
-                                   boolean is_inv = p.contains("_MASK_");
-                                   if (((lval >> i) & 0x1) == (is_inv ? 0 : 1))
-                                       tfeat.add(name + "." + p + (is_inv ? "_INV" : "") + "[" + i + "]");
-                               }
-                           }
-                       }
-                       EDIFPropertyValue asl = c.getProperty("AUTO_SLEEP_LATENCY");
-                       if (asl != null) {
-                           int a = Integer.parseInt(asl.getValue());
-                           for (int i = 0; i < 4; i++)
-                               if (((a >> i) & 0x1) == 1) {
-                                   tfeat.add(name + ".AUTO_SLEEP_LATENCY[" + i + "]");
-                               }
-                       }
-
-                       for (EDIFPortInst epi : c.getEDIFCellInst().getPortInsts()) {
-                           if (epi.isOutput() && epi.getNet() != null)
-                               tfeat.add(name + "." + epi.getName() + ".USED");
-                       }
-                   }
-                }
-                FileWriter vf = new FileWriter(f.getAbsolutePath().replace(".dcp", ".features"), false);
-                PrintWriter v = new PrintWriter(vf);
-                for (Tile t : des.getDevice().getAllTiles()) {
-                    TileTypeEnum tt = t.getTileTypeEnum();
-                    if (tt == TileTypeEnum.BRAM || tt == TileTypeEnum.DSP || tt == TileTypeEnum.DSP_L || tt == TileTypeEnum.DSP_R ||
-                        tt == TileTypeEnum.URAM_URAM_FT || tt == TileTypeEnum.URAM_URAM_DELAY_FT) {
-                        String tname = t.getName() + ":" + tt.toString();
-                        if (!pips_by_tile.containsKey(tname) && !sitefeatures_by_tile.containsKey(tname))
-                            continue;
-                        v.println(".tile " + tname);
-                        if (pips_by_tile.containsKey(tname))
-                            for (String p : pips_by_tile.get(tname))
-                                v.println(p);
-                        if (sitefeatures_by_tile.containsKey(tname))
-                            for (String sf : sitefeatures_by_tile.get(tname))
-                                v.println(sf);
+                    for (EDIFPortInst epi : c.getEDIFCellInst().getPortInsts()) {
+                        if (epi.isOutput() && epi.getNet() != null)
+                            tfeat.add(name + "." + epi.getName() + ".USED");
                     }
                 }
-                vf.close();
             }
+            FileWriter vf = new FileWriter(f.replace(".dcp", ".features"), false);
+            PrintWriter v = new PrintWriter(vf);
+            for (Tile t : des.getDevice().getAllTiles()) {
+                TileTypeEnum tt = t.getTileTypeEnum();
+                if (tt == TileTypeEnum.BRAM || tt == TileTypeEnum.DSP || tt == TileTypeEnum.DSP_L || tt == TileTypeEnum.DSP_R ||
+                    tt == TileTypeEnum.URAM_URAM_FT || tt == TileTypeEnum.URAM_URAM_DELAY_FT) {
+                    String tname = t.getName() + ":" + tt.toString();
+                    if (!pips_by_tile.containsKey(tname) && !sitefeatures_by_tile.containsKey(tname))
+                        continue;
+                    v.println(".tile " + tname);
+                    if (pips_by_tile.containsKey(tname))
+                        for (String p : pips_by_tile.get(tname))
+                            v.println(p);
+                    if (sitefeatures_by_tile.containsKey(tname))
+                        for (String sf : sitefeatures_by_tile.get(tname))
+                            v.println(sf);
+                }
+            }
+            vf.close();
         }
-
     }
 }
diff --git a/dump_clocking.java b/dump_clocking.java
index 0a31017..d8ff310 100644
--- a/dump_clocking.java
+++ b/dump_clocking.java
@@ -12,15 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package dev.fpga.rapidwright;
-
 import com.xilinx.rapidwright.design.*;
 import com.xilinx.rapidwright.design.tools.LUTTools;
 import com.xilinx.rapidwright.device.*;
 import com.xilinx.rapidwright.edif.EDIFName;
 import com.xilinx.rapidwright.edif.EDIFPort;
 import com.xilinx.rapidwright.edif.EDIFPortInst;
-import org.python.bouncycastle.crypto.tls.DefaultTlsCipherFactory;
 
 import java.io.File;
 import java.io.FileWriter;
@@ -123,347 +120,340 @@
 
 
     public static void main(String[] args) throws IOException {
-
-
-        Scanner scanner = new Scanner(new File("/invpips.txt"));
+        Scanner scanner = new Scanner(new File("invpips.txt"));
         while (scanner.hasNextLine()) {
             String nl = scanner.nextLine().trim();
             inverted_pips.add(nl);
         }
 
-        File folder = new File("/specimen_clk");
-        File[] listOfFiles = folder.listFiles();
-        for (File f : listOfFiles) {
-            if (f.getName().endsWith(".dcp")) {
-                Design des = Design.readCheckpoint(f.getAbsolutePath());
-                HashMap<String, ArrayList<String>> pips_by_tile = new HashMap<>();
-                HashMap<String, ArrayList<String>> sitefeatures_by_tile = new HashMap<>();
-                for (Net n : des.getNets()) {
+        for (String f : args) {
+            Design des = Design.readCheckpoint(f);
+            HashMap<String, ArrayList<String>> pips_by_tile = new HashMap<>();
+            HashMap<String, ArrayList<String>> sitefeatures_by_tile = new HashMap<>();
+            for (Net n : des.getNets()) {
 
-                    HashMap<Node, PIP> uphill = new HashMap<>();
-                    HashSet<Node> allnodes = new HashSet<>();
+                HashMap<Node, PIP> uphill = new HashMap<>();
+                HashSet<Node> allnodes = new HashSet<>();
 
-                    if (n.getSource() != null)
-                        uphill.put(n.getSource().getConnectedNode(), null);
-                    int max_distr_depth = 0;
-                    for (PIP p : n.getPIPs()) {
-                        if (!p.isBidirectional()) {
-                            uphill.put(p.getEndNode(), p);
-                        }
+                if (n.getSource() != null)
+                    uphill.put(n.getSource().getConnectedNode(), null);
+                int max_distr_depth = 0;
+                for (PIP p : n.getPIPs()) {
+                    if (!p.isBidirectional()) {
+                        uphill.put(p.getEndNode(), p);
+                    }
 
-                        allnodes.add(p.getStartNode());
-                        allnodes.add(p.getEndNode());
+                    allnodes.add(p.getStartNode());
+                    allnodes.add(p.getEndNode());
 
-                        TileTypeEnum ptt = p.getTile().getTileTypeEnum();
-                        if (ptt == TileTypeEnum.RCLK_INT_L || ptt == TileTypeEnum.RCLK_INT_R) {
-                            if (p.getEndWireName().startsWith("CLK_LEAF_SITES_") && p.getEndWireName().endsWith("_CLK_LEAF")) {
-                                String tile = p.getTile().getName() + ":" + p.getTile().getTileTypeEnum().toString();
-                                if (!pips_by_tile.containsKey(tile))
-                                    pips_by_tile.put(tile, new ArrayList<>());
-                                pips_by_tile.get(tile).add("WIRE." + p.getEndWireName() + ".DRIVEN");
-                                if (p.getStartWireName().endsWith("_CLK_IN") && p.isRouteThru()) {
-                                    String site = site_index_in_tile(p.getTile(), p.getStartNode().getSitePin().getSite());
-                                    if (!sitefeatures_by_tile.containsKey(tile))
-                                        sitefeatures_by_tile.put(tile, new ArrayList<>());
-                                    sitefeatures_by_tile.get(tile).add(site + ".BUFCE_LEAF.IN_USE");
+                    TileTypeEnum ptt = p.getTile().getTileTypeEnum();
+                    if (ptt == TileTypeEnum.RCLK_INT_L || ptt == TileTypeEnum.RCLK_INT_R) {
+                        if (p.getEndWireName().startsWith("CLK_LEAF_SITES_") && p.getEndWireName().endsWith("_CLK_LEAF")) {
+                            String tile = p.getTile().getName() + ":" + p.getTile().getTileTypeEnum().toString();
+                            if (!pips_by_tile.containsKey(tile))
+                                pips_by_tile.put(tile, new ArrayList<>());
+                            pips_by_tile.get(tile).add("WIRE." + p.getEndWireName() + ".DRIVEN");
+                            if (p.getStartWireName().endsWith("_CLK_IN") && p.isRouteThru()) {
+                                String site = site_index_in_tile(p.getTile(), p.getStartNode().getSitePin().getSite());
+                                if (!sitefeatures_by_tile.containsKey(tile))
+                                    sitefeatures_by_tile.put(tile, new ArrayList<>());
+                                sitefeatures_by_tile.get(tile).add(site + ".BUFCE_LEAF.IN_USE");
 
 
-                                    if (n.getName().startsWith("leaf_delay_")) {
-                                        int count = 0;
-                                        for (PIP p2 : n.getPIPs()) {
-                                            if (p2.getEndWireName().startsWith("CLK_LEAF_SITES_") && p2.getEndWireName().endsWith("_CLK_LEAF") && p2.getStartWireName().endsWith("_CLK_IN"))
-                                                ++count;
-                                        }
-                                        if (count == 1) {
-                                            int value = Integer.parseInt(n.getName().split("_")[2]);
-                                            sitefeatures_by_tile.get(tile).add(site + ".BUFCE_LEAF.DELAY_TAP_" + value);
-                                        }
-                                        if (is_node_inverted(n, p.getStartNode())) {
-                                            sitefeatures_by_tile.get(tile).add(site + ".BUFCE_LEAF.IINV.1");
-                                        }
+                                if (n.getName().startsWith("leaf_delay_")) {
+                                    int count = 0;
+                                    for (PIP p2 : n.getPIPs()) {
+                                        if (p2.getEndWireName().startsWith("CLK_LEAF_SITES_") && p2.getEndWireName().endsWith("_CLK_LEAF") && p2.getStartWireName().endsWith("_CLK_IN"))
+                                            ++count;
+                                    }
+                                    if (count == 1) {
+                                        int value = Integer.parseInt(n.getName().split("_")[2]);
+                                        sitefeatures_by_tile.get(tile).add(site + ".BUFCE_LEAF.DELAY_TAP_" + value);
+                                    }
+                                    if (is_node_inverted(n, p.getStartNode())) {
+                                        sitefeatures_by_tile.get(tile).add(site + ".BUFCE_LEAF.IINV.1");
                                     }
                                 }
                             }
                         }
-                        if (p.getStartWire().getWireName().contains("BUFCE_ROW_FSR") && p.getStartWire().getWireName().endsWith("CLK_IN")) {
-                            max_distr_depth = Math.max(max_distr_depth, get_clock_depth(n, p.getStartNode()));
-                        }
                     }
-
-                    for (Node node : allnodes) {
-                        for (Wire w : node.getAllWiresInNode()) {
-                            TileTypeEnum wtt = w.getTile().getTileTypeEnum();
-                            if (wtt == TileTypeEnum.RCLK_BRAM_INTF_L || wtt == TileTypeEnum.RCLK_BRAM_INTF_TD_L || wtt == TileTypeEnum.RCLK_BRAM_INTF_TD_R ||
-                                    wtt == TileTypeEnum.RCLK_CLEL_L_L || wtt == TileTypeEnum.RCLK_CLEL_L || wtt == TileTypeEnum.RCLK_CLEL_L_R ||
-                                    wtt == TileTypeEnum.RCLK_CLEM_CLKBUF_L || wtt == TileTypeEnum.RCLK_CLEM_L || wtt == TileTypeEnum.RCLK_DSP_INTF_L ||
-                                    wtt == TileTypeEnum.RCLK_DSP_INTF_R || wtt == TileTypeEnum.RCLK_RCLK_URAM_INTF_L_FT ||
-                                    wtt == TileTypeEnum.RCLK_CLEM_R || wtt == TileTypeEnum.RCLK_CLEL_R || wtt == TileTypeEnum.GTH_QUAD_RIGHT) {
-                                if (w.getWireName().startsWith("CLK_TEST_BUF_SITE_") || w.getWireName().startsWith("CLK_HROUTE_CORE_OPT") ||
-                                    w.getWireName().startsWith("CLK_VDISTR_BOT") || w.getWireName().startsWith("CLK_VDISTR_TOP") ||
-                                        w.getWireName().startsWith("CLK_VROUTE_BOT") || w.getWireName().startsWith("CLK_VROUTE_TOP")) {
-                                    String tile = w.getTile().getName() + ":" + w.getTile().getTileTypeEnum().toString();
-                                    if (!pips_by_tile.containsKey(tile))
-                                        pips_by_tile.put(tile, new ArrayList<>());
-                                    pips_by_tile.get(tile).add("WIRE." + w.getWireName() + ".USED");
-                                }
-                            }
-                            if (wtt == TileTypeEnum.RCLK_DSP_INTF_CLKBUF_L || wtt == TileTypeEnum.RCLK_CLEM_CLKBUF_L || wtt == TileTypeEnum.RCLK_BRAM_INTF_L ||
-                                wtt == TileTypeEnum.RCLK_RCLK_XIPHY_INNER_FT || wtt == TileTypeEnum.RCLK_HDIO  || wtt == TileTypeEnum.GTH_QUAD_RIGHT) {
-                                if (w.getWireName().startsWith("CLK_HROUTE") || w.getWireName().startsWith("CLK_HDISTR")) {
-                                    String tile = w.getTile().getName() + ":" + w.getTile().getTileTypeEnum().toString();
-                                    if (!pips_by_tile.containsKey(tile))
-                                        pips_by_tile.put(tile, new ArrayList<>());
-                                    pips_by_tile.get(tile).add("WIRE." + w.getWireName() + ".USED");
-                                }
-                            }
-                            if (wtt == TileTypeEnum.CMT_L) {
-                                //CLK_HROUTE_
-                                if (w.getWireName().startsWith("CLK_HROUTE_") || w.getWireName().startsWith("CLK_HDISTR_") || w.getWireName().startsWith("CLK_VDISTR_") ||
-                                        w.getWireName().startsWith("CLK_TEST_BUF_SITE_")) {
-                                    String tile = w.getTile().getName() + ":" + w.getTile().getTileTypeEnum().toString();
-                                    if (!pips_by_tile.containsKey(tile))
-                                        pips_by_tile.put(tile, new ArrayList<>());
-                                    pips_by_tile.get(tile).add("WIRE." + w.getWireName() + ".USED");
-                                }
-                            }
-                        }
+                    if (p.getStartWire().getWireName().contains("BUFCE_ROW_FSR") && p.getStartWire().getWireName().endsWith("CLK_IN")) {
+                        max_distr_depth = Math.max(max_distr_depth, get_clock_depth(n, p.getStartNode()));
                     }
+                }
 
-                    for (PIP p : n.getPIPs()) {
-
-                        String tile = p.getTile().getName() + ":" + p.getTile().getTileTypeEnum().toString();
-                        if (p.getTile().getTileTypeEnum() == TileTypeEnum.BRAM || p.getTile().getTileTypeEnum() == TileTypeEnum.INT)
-                            continue;
-                        if (!pips_by_tile.containsKey(tile))
-                            pips_by_tile.put(tile, new ArrayList<>());
-                        if (p.isBidirectional()) {
-                            Node cursor = p.getStartNode();
-                            boolean is_fwd = false;
-                            if (uphill.containsKey(p.getStartNode())) {
-                                is_fwd = true;
-                                uphill.put(p.getEndNode(), p);
-                            } else if (uphill.containsKey(p.getEndNode())) {
-                                is_fwd = false;
-                                uphill.put(p.getStartNode(), p);
-                            } else {
-                                continue;
+                for (Node node : allnodes) {
+                    for (Wire w : node.getAllWiresInNode()) {
+                        TileTypeEnum wtt = w.getTile().getTileTypeEnum();
+                        if (wtt == TileTypeEnum.RCLK_BRAM_INTF_L || wtt == TileTypeEnum.RCLK_BRAM_INTF_TD_L || wtt == TileTypeEnum.RCLK_BRAM_INTF_TD_R ||
+                                wtt == TileTypeEnum.RCLK_CLEL_L_L || wtt == TileTypeEnum.RCLK_CLEL_L || wtt == TileTypeEnum.RCLK_CLEL_L_R ||
+                                wtt == TileTypeEnum.RCLK_CLEM_CLKBUF_L || wtt == TileTypeEnum.RCLK_CLEM_L || wtt == TileTypeEnum.RCLK_DSP_INTF_L ||
+                                wtt == TileTypeEnum.RCLK_DSP_INTF_R || wtt == TileTypeEnum.RCLK_RCLK_URAM_INTF_L_FT ||
+                                wtt == TileTypeEnum.RCLK_CLEM_R || wtt == TileTypeEnum.RCLK_CLEL_R || wtt == TileTypeEnum.GTH_QUAD_RIGHT) {
+                            if (w.getWireName().startsWith("CLK_TEST_BUF_SITE_") || w.getWireName().startsWith("CLK_HROUTE_CORE_OPT") ||
+                                w.getWireName().startsWith("CLK_VDISTR_BOT") || w.getWireName().startsWith("CLK_VDISTR_TOP") ||
+                                    w.getWireName().startsWith("CLK_VROUTE_BOT") || w.getWireName().startsWith("CLK_VROUTE_TOP")) {
+                                String tile = w.getTile().getName() + ":" + w.getTile().getTileTypeEnum().toString();
+                                if (!pips_by_tile.containsKey(tile))
+                                    pips_by_tile.put(tile, new ArrayList<>());
+                                pips_by_tile.get(tile).add("WIRE." + w.getWireName() + ".USED");
                             }
-                            pips_by_tile.get(tile).add("PIP." + p.getEndWireName() + "." + p.getStartWireName() + (is_fwd ? ".FWD" : ".REV"));
-                        } else {
-                            pips_by_tile.get(tile).add("PIP." + p.getEndWireName() + "." + p.getStartWireName());
                         }
-                        if (n.getName().contains("clk_dly_fuzz") && p.getStartWire().getWireName().contains("BUFCE_ROW_FSR") && p.getStartWire().getWireName().endsWith("CLK_IN")) {
-                            int depth = get_clock_depth(n, p.getStartNode());
-                            int tap = max_distr_depth - depth;
-                            String bufce_name = site_index_in_tile(p.getTile(), p.getStartNode().getSitePin().getSite());
-                            for (int i = 0; i < 3; i++) {
-                                if (((tap >> i) & 0x1) == 1) {
-                                    pips_by_tile.get(tile).add(bufce_name + ".COMP_DELAY_TAP[" + i + "]");
-                                }
+                        if (wtt == TileTypeEnum.RCLK_DSP_INTF_CLKBUF_L || wtt == TileTypeEnum.RCLK_CLEM_CLKBUF_L || wtt == TileTypeEnum.RCLK_BRAM_INTF_L ||
+                            wtt == TileTypeEnum.RCLK_RCLK_XIPHY_INNER_FT || wtt == TileTypeEnum.RCLK_HDIO  || wtt == TileTypeEnum.GTH_QUAD_RIGHT) {
+                            if (w.getWireName().startsWith("CLK_HROUTE") || w.getWireName().startsWith("CLK_HDISTR")) {
+                                String tile = w.getTile().getName() + ":" + w.getTile().getTileTypeEnum().toString();
+                                if (!pips_by_tile.containsKey(tile))
+                                    pips_by_tile.put(tile, new ArrayList<>());
+                                pips_by_tile.get(tile).add("WIRE." + w.getWireName() + ".USED");
+                            }
+                        }
+                        if (wtt == TileTypeEnum.CMT_L) {
+                            //CLK_HROUTE_
+                            if (w.getWireName().startsWith("CLK_HROUTE_") || w.getWireName().startsWith("CLK_HDISTR_") || w.getWireName().startsWith("CLK_VDISTR_") ||
+                                    w.getWireName().startsWith("CLK_TEST_BUF_SITE_")) {
+                                String tile = w.getTile().getName() + ":" + w.getTile().getTileTypeEnum().toString();
+                                if (!pips_by_tile.containsKey(tile))
+                                    pips_by_tile.put(tile, new ArrayList<>());
+                                pips_by_tile.get(tile).add("WIRE." + w.getWireName() + ".USED");
                             }
                         }
                     }
                 }
-                for (SiteInst si : des.getSiteInsts()) {
-                    String tile = si.getTile().getName() + ":" + si.getTile().getTileTypeEnum().toString();
+
+                for (PIP p : n.getPIPs()) {
+
+                    String tile = p.getTile().getName() + ":" + p.getTile().getTileTypeEnum().toString();
+                    if (p.getTile().getTileTypeEnum() == TileTypeEnum.BRAM || p.getTile().getTileTypeEnum() == TileTypeEnum.INT)
+                        continue;
+                    if (!pips_by_tile.containsKey(tile))
+                        pips_by_tile.put(tile, new ArrayList<>());
+                    if (p.isBidirectional()) {
+                        Node cursor = p.getStartNode();
+                        boolean is_fwd = false;
+                        if (uphill.containsKey(p.getStartNode())) {
+                            is_fwd = true;
+                            uphill.put(p.getEndNode(), p);
+                        } else if (uphill.containsKey(p.getEndNode())) {
+                            is_fwd = false;
+                            uphill.put(p.getStartNode(), p);
+                        } else {
+                            continue;
+                        }
+                        pips_by_tile.get(tile).add("PIP." + p.getEndWireName() + "." + p.getStartWireName() + (is_fwd ? ".FWD" : ".REV"));
+                    } else {
+                        pips_by_tile.get(tile).add("PIP." + p.getEndWireName() + "." + p.getStartWireName());
+                    }
+                    if (n.getName().contains("clk_dly_fuzz") && p.getStartWire().getWireName().contains("BUFCE_ROW_FSR") && p.getStartWire().getWireName().endsWith("CLK_IN")) {
+                        int depth = get_clock_depth(n, p.getStartNode());
+                        int tap = max_distr_depth - depth;
+                        String bufce_name = site_index_in_tile(p.getTile(), p.getStartNode().getSitePin().getSite());
+                        for (int i = 0; i < 3; i++) {
+                            if (((tap >> i) & 0x1) == 1) {
+                                pips_by_tile.get(tile).add(bufce_name + ".COMP_DELAY_TAP[" + i + "]");
+                            }
+                        }
+                    }
+                }
+            }
+            for (SiteInst si : des.getSiteInsts()) {
+                String tile = si.getTile().getName() + ":" + si.getTile().getTileTypeEnum().toString();
+                if (!sitefeatures_by_tile.containsKey(tile))
+                    sitefeatures_by_tile.put(tile, new ArrayList<>());
+                ArrayList<String> tfeat = sitefeatures_by_tile.get(tile);
+                if (si.getSiteTypeEnum() == SiteTypeEnum.BUFCE_LEAF) {
+                    String name = site_index_in_tile(si.getTile(), si.getSite());
+                    for (Cell c : si.getCells()) {
+                        if (c.getType() != null && c.getType().equals("BUFCE_LEAF")) {
+                            tfeat.add(name + ".BUFCE_LEAF.IN_USE");
+                            if (c.getProperty("CE_TYPE") != null)
+                                tfeat.add(name + ".BUFCE_LEAF.CE_TYPE." + c.getProperty("CE_TYPE").getValue());
+                            var all_props = c.getProperties();
+                            for (var e : all_props.entrySet()) {
+                                String propname = e.getKey().getName();
+                                if (propname.startsWith("IS_") && propname.endsWith("_INVERTED")) {
+                                    String pinname = propname.substring(3, propname.length() - 9);
+                                    String v = e.getValue().getValue();
+                                    int base_pos = v.indexOf("'b");
+                                    if (base_pos != -1)
+                                        v = v.substring(base_pos + 2);
+                                    if (pinname.equals("I"))
+                                        if (is_sink_inverted(si.getSitePinInst("CLK_IN")))
+                                            v = (v.equals("1") ? "0" : "1");
+                                    tfeat.add(name + ".BUFCE_LEAF." + pinname + "INV." + v);
+                                }
+                            }
+                        }
+                    }
+                } else if (si.getSiteTypeEnum() == SiteTypeEnum.BUFCE_ROW_FSR) {
+                    for (Cell c : si.getCells()) {
+                        if (c.getType().equals("<LOCKED>"))
+                            System.out.println(c.getBELName());
+                    }
+                } else if (si.getSiteTypeEnum() == SiteTypeEnum.BUFGCE || si.getSiteTypeEnum() == SiteTypeEnum.BUFGCE_DIV) {
+                    String name = site_index_in_tile(si.getTile(), si.getSite());
+                    for (Cell c : si.getCells()) {
+                        if (c.getType() != null && c.getType().startsWith("BUFGCE")) {
+                            tfeat.add(name + "." + c.getType() + ".IN_USE");
+                            var all_props = c.getProperties();
+                            for (var e : all_props.entrySet()) {
+                                String propname = e.getKey().getName();
+                                String v = e.getValue().getValue();
+                                int base_pos = v.indexOf("'b");
+                                if (base_pos != -1)
+                                    v = v.substring(base_pos + 2);
+                                if (propname.startsWith("IS_") && propname.endsWith("_INVERTED")) {
+                                    String pinname = propname.substring(3, propname.length() - 9);
+                                    if (pinname.equals("I")) {
+                                        if (is_sink_inverted(si.getSitePinInst("CLK_IN")))
+                                            v = (v.equals("1") ? "0" : "1");
+                                        String sw = c.getSiteWireNameFromLogicalPin(pinname);
+                                        if (sw == null || si.getNetFromSiteWire(sw) == null || si.getNetFromSiteWire(sw).isStaticNet())
+                                            continue;
+                                    }
+                                    tfeat.add(name + "." + si.getSiteTypeEnum().toString() + "." + pinname + "INV." + v);
+                                } else if ((si.getSiteTypeEnum() == SiteTypeEnum.BUFGCE && propname.equals("CE_TYPE")) || propname.equals("BUFGCE_DIVIDE")) {
+                                    tfeat.add(name +  "." + si.getSiteTypeEnum().toString() + "." + propname + "." + v);
+                                }
+                            }
+                        }
+                    }
+                } else if (si.getSiteTypeEnum() == SiteTypeEnum.BUFGCTRL) {
+                    String name = site_index_in_tile(si.getTile(), si.getSite());
+                    for (Cell c : si.getCells()) {
+                        if (c.getType() != null && c.getType().startsWith("BUFGCTRL")) {
+                            tfeat.add(name + "." + c.getType() + ".IN_USE");
+                            var all_props = c.getProperties();
+                            for (var e : all_props.entrySet()) {
+                                String propname = e.getKey().getName();
+                                String v = e.getValue().getValue();
+                                int base_pos = v.indexOf("'b");
+                                if (base_pos != -1)
+                                    v = v.substring(base_pos + 2);
+                                if (propname.startsWith("IS_") && propname.endsWith("_INVERTED")) {
+                                    String pinname = propname.substring(3, propname.length() - 9);
+                                    if (pinname.equals("I0") || pinname.equals("I1")) {
+                                        String sw = c.getSiteWireNameFromLogicalPin(pinname);
+                                        if (sw == null || si.getNetFromSiteWire(sw) == null || si.getNetFromSiteWire(sw).isStaticNet())
+                                            continue;
+                                        if (is_sink_inverted(si.getSitePinInst("CLK_" + pinname)))
+                                            v = (v.equals("1") ? "0" : "1");
+                                    }
+                                    tfeat.add(name + "." + si.getSiteTypeEnum().toString() + "." + pinname + "INV." + v);
+                                } else if (propname.equals("INIT_OUT") || propname.startsWith("PRESELECT_")) {
+                                    tfeat.add(name +  "." + si.getSiteTypeEnum().toString() + "." + propname + "." + v);
+                                }
+                            }
+                        }
+                    }
+                } else if (si.getSiteTypeEnum() == SiteTypeEnum.MMCM) {
+                    String name = site_index_in_tile(si.getTile(), si.getSite());
+                    Cell c = si.getCell("MMCM");
+                    if (c == null || c.getType() == null)
+                        continue;
+                    tfeat.add(name + ".IN_USE");
+                    var all_props = c.getProperties();
+                    for (var e : all_props.entrySet()) {
+                        String propname = e.getKey().getName();
+                        String v = e.getValue().getValue();
+                        int base_pos = v.indexOf("'b");
+                        if (base_pos != -1)
+                            v = v.substring(base_pos + 2);
+                        if (propname.startsWith("IS_") && propname.endsWith("_INVERTED")) {
+                            String pinname = propname.substring(3, propname.length() - 9);
+                            if (pinname.equals("CLKIN1") || pinname.equals("CLKIN2") || pinname.equals("CLKFBIN"))
+                                continue;
+                            String sw = c.getSiteWireNameFromLogicalPin(pinname);
+                            if (sw == null || si.getNetFromSiteWire(sw) == null || si.getNetFromSiteWire(sw).isStaticNet())
+                                continue;
+                            tfeat.add(name + "." + si.getSiteTypeEnum().toString() + "." + pinname + "INV." + v);
+                        } else if (propname.equals("COMPENSATION")) {
+                            tfeat.add(name +  "." + si.getSiteTypeEnum().toString() + "." + propname + "." + v);
+                        }
+                    }
+                } else if (si.getSiteTypeEnum() == SiteTypeEnum.PLL) {
+                    String name = site_index_in_tile(si.getTile(), si.getSite());
+                    Cell c = si.getCell("PLL");
+                    if (c == null || c.getType() == null)
+                        continue;
+                    tfeat.add(name + ".IN_USE");
+                    var all_props = c.getProperties();
+                    for (var e : all_props.entrySet()) {
+                        String propname = e.getKey().getName();
+                        String v = e.getValue().getValue();
+                        int base_pos = v.indexOf("'b");
+                        if (base_pos != -1)
+                            v = v.substring(base_pos + 2);
+                        if (propname.startsWith("IS_") && propname.endsWith("_INVERTED")) {
+                            String pinname = propname.substring(3, propname.length() - 9);
+                            if (pinname.equals("CLKIN") || pinname.equals("CLKFBIN"))
+                                continue;
+                            String sw = c.getSiteWireNameFromLogicalPin(pinname);
+                            if (sw == null || si.getNetFromSiteWire(sw) == null || si.getNetFromSiteWire(sw).isStaticNet())
+                                continue;
+                            tfeat.add(name + "." + si.getSiteTypeEnum().toString() + "." + pinname + "INV." + v);
+                        } else if (propname.equals("COMPENSATION")) {
+                            tfeat.add(name +  "." + si.getSiteTypeEnum().toString() + "." + propname + "." + v);
+                        }
+                    }
+                }
+            }
+            for (Tile t : des.getDevice().getAllTiles()) {
+                if (t.getTileTypeEnum() != TileTypeEnum.RCLK_HPIO_L)
+                    continue;
+                boolean dci_used = false;
+                Tile[] io_tiles = {des.getDevice().getTile(t.getRow()+30, t.getColumn()), des.getDevice().getTile(t.getRow()-1, t.getColumn())};
+                for (Tile iot : io_tiles) {
+                    for (Site s : iot.getSites()) {
+                        SiteInst si = des.getSiteInstFromSite(s);
+                        if (si == null)
+                            continue;
+                        Cell pad = si.getCell(si.getBEL("PAD"));
+                        if (pad == null)
+                            continue;
+                        EDIFPort p = des.getTopEDIFCell().getPort(pad.getName());
+                        if (des.getTopEDIFCell().getNet(pad.getName()) == null)
+                            continue;
+                        var prop = des.getTopEDIFCell().getNet(pad.getName()).getProperties();
+                        if (prop == null || !prop.containsKey(new EDIFName("IOSTANDARD")))
+                            continue;
+                        String iostd = prop.get(new EDIFName("IOSTANDARD")).getValue();
+                        if (iostd.contains("POD12_DCI") && !f.contains("ipi")) // FIXME: find out why this loses bits
+                            dci_used = true;
+                    }
+                }
+                if (dci_used) {
+                    String tile = t.getName() + ":" + t.getTileTypeEnum().toString();
                     if (!sitefeatures_by_tile.containsKey(tile))
                         sitefeatures_by_tile.put(tile, new ArrayList<>());
                     ArrayList<String> tfeat = sitefeatures_by_tile.get(tile);
-                    if (si.getSiteTypeEnum() == SiteTypeEnum.BUFCE_LEAF) {
-                        String name = site_index_in_tile(si.getTile(), si.getSite());
-                        for (Cell c : si.getCells()) {
-                            if (c.getType() != null && c.getType().equals("BUFCE_LEAF")) {
-                                tfeat.add(name + ".BUFCE_LEAF.IN_USE");
-                                if (c.getProperty("CE_TYPE") != null)
-                                    tfeat.add(name + ".BUFCE_LEAF.CE_TYPE." + c.getProperty("CE_TYPE").getValue());
-                                var all_props = c.getProperties();
-                                for (var e : all_props.entrySet()) {
-                                    String propname = e.getKey().getName();
-                                    if (propname.startsWith("IS_") && propname.endsWith("_INVERTED")) {
-                                        String pinname = propname.substring(3, propname.length() - 9);
-                                        String v = e.getValue().getValue();
-                                        int base_pos = v.indexOf("'b");
-                                        if (base_pos != -1)
-                                            v = v.substring(base_pos + 2);
-                                        if (pinname.equals("I"))
-                                            if (is_sink_inverted(si.getSitePinInst("CLK_IN")))
-                                                v = (v.equals("1") ? "0" : "1");
-                                        tfeat.add(name + ".BUFCE_LEAF." + pinname + "INV." + v);
-                                    }
-                                }
-                            }
-                        }
-                    } else if (si.getSiteTypeEnum() == SiteTypeEnum.BUFCE_ROW_FSR) {
-                        for (Cell c : si.getCells()) {
-                            if (c.getType().equals("<LOCKED>"))
-                                System.out.println(c.getBELName());
-                        }
-                    } else if (si.getSiteTypeEnum() == SiteTypeEnum.BUFGCE || si.getSiteTypeEnum() == SiteTypeEnum.BUFGCE_DIV) {
-                        String name = site_index_in_tile(si.getTile(), si.getSite());
-                        for (Cell c : si.getCells()) {
-                            if (c.getType() != null && c.getType().startsWith("BUFGCE")) {
-                                tfeat.add(name + "." + c.getType() + ".IN_USE");
-                                var all_props = c.getProperties();
-                                for (var e : all_props.entrySet()) {
-                                    String propname = e.getKey().getName();
-                                    String v = e.getValue().getValue();
-                                    int base_pos = v.indexOf("'b");
-                                    if (base_pos != -1)
-                                        v = v.substring(base_pos + 2);
-                                    if (propname.startsWith("IS_") && propname.endsWith("_INVERTED")) {
-                                        String pinname = propname.substring(3, propname.length() - 9);
-                                        if (pinname.equals("I")) {
-                                            if (is_sink_inverted(si.getSitePinInst("CLK_IN")))
-                                                v = (v.equals("1") ? "0" : "1");
-                                            String sw = c.getSiteWireNameFromLogicalPin(pinname);
-                                            if (sw == null || si.getNetFromSiteWire(sw) == null || si.getNetFromSiteWire(sw).isStaticNet())
-                                                continue;
-                                        }
-                                        tfeat.add(name + "." + si.getSiteTypeEnum().toString() + "." + pinname + "INV." + v);
-                                    } else if ((si.getSiteTypeEnum() == SiteTypeEnum.BUFGCE && propname.equals("CE_TYPE")) || propname.equals("BUFGCE_DIVIDE")) {
-                                        tfeat.add(name +  "." + si.getSiteTypeEnum().toString() + "." + propname + "." + v);
-                                    }
-                                }
-                            }
-                        }
-                    } else if (si.getSiteTypeEnum() == SiteTypeEnum.BUFGCTRL) {
-                        String name = site_index_in_tile(si.getTile(), si.getSite());
-                        for (Cell c : si.getCells()) {
-                            if (c.getType() != null && c.getType().startsWith("BUFGCTRL")) {
-                                tfeat.add(name + "." + c.getType() + ".IN_USE");
-                                var all_props = c.getProperties();
-                                for (var e : all_props.entrySet()) {
-                                    String propname = e.getKey().getName();
-                                    String v = e.getValue().getValue();
-                                    int base_pos = v.indexOf("'b");
-                                    if (base_pos != -1)
-                                        v = v.substring(base_pos + 2);
-                                    if (propname.startsWith("IS_") && propname.endsWith("_INVERTED")) {
-                                        String pinname = propname.substring(3, propname.length() - 9);
-                                        if (pinname.equals("I0") || pinname.equals("I1")) {
-                                            String sw = c.getSiteWireNameFromLogicalPin(pinname);
-                                            if (sw == null || si.getNetFromSiteWire(sw) == null || si.getNetFromSiteWire(sw).isStaticNet())
-                                                continue;
-                                            if (is_sink_inverted(si.getSitePinInst("CLK_" + pinname)))
-                                                v = (v.equals("1") ? "0" : "1");
-                                        }
-                                        tfeat.add(name + "." + si.getSiteTypeEnum().toString() + "." + pinname + "INV." + v);
-                                    } else if (propname.equals("INIT_OUT") || propname.startsWith("PRESELECT_")) {
-                                        tfeat.add(name +  "." + si.getSiteTypeEnum().toString() + "." + propname + "." + v);
-                                    }
-                                }
-                            }
-                        }
-                    } else if (si.getSiteTypeEnum() == SiteTypeEnum.MMCM) {
-                        String name = site_index_in_tile(si.getTile(), si.getSite());
-                        Cell c = si.getCell("MMCM");
-                        if (c == null || c.getType() == null)
-                            continue;
-                        tfeat.add(name + ".IN_USE");
-                        var all_props = c.getProperties();
-                        for (var e : all_props.entrySet()) {
-                            String propname = e.getKey().getName();
-                            String v = e.getValue().getValue();
-                            int base_pos = v.indexOf("'b");
-                            if (base_pos != -1)
-                                v = v.substring(base_pos + 2);
-                            if (propname.startsWith("IS_") && propname.endsWith("_INVERTED")) {
-                                String pinname = propname.substring(3, propname.length() - 9);
-                                if (pinname.equals("CLKIN1") || pinname.equals("CLKIN2") || pinname.equals("CLKFBIN"))
-                                    continue;
-                                String sw = c.getSiteWireNameFromLogicalPin(pinname);
-                                if (sw == null || si.getNetFromSiteWire(sw) == null || si.getNetFromSiteWire(sw).isStaticNet())
-                                    continue;
-                                tfeat.add(name + "." + si.getSiteTypeEnum().toString() + "." + pinname + "INV." + v);
-                            } else if (propname.equals("COMPENSATION")) {
-                                tfeat.add(name +  "." + si.getSiteTypeEnum().toString() + "." + propname + "." + v);
-                            }
-                        }
-                    } else if (si.getSiteTypeEnum() == SiteTypeEnum.PLL) {
-                        String name = site_index_in_tile(si.getTile(), si.getSite());
-                        Cell c = si.getCell("PLL");
-                        if (c == null || c.getType() == null)
-                            continue;
-                        tfeat.add(name + ".IN_USE");
-                        var all_props = c.getProperties();
-                        for (var e : all_props.entrySet()) {
-                            String propname = e.getKey().getName();
-                            String v = e.getValue().getValue();
-                            int base_pos = v.indexOf("'b");
-                            if (base_pos != -1)
-                                v = v.substring(base_pos + 2);
-                            if (propname.startsWith("IS_") && propname.endsWith("_INVERTED")) {
-                                String pinname = propname.substring(3, propname.length() - 9);
-                                if (pinname.equals("CLKIN") || pinname.equals("CLKFBIN"))
-                                    continue;
-                                String sw = c.getSiteWireNameFromLogicalPin(pinname);
-                                if (sw == null || si.getNetFromSiteWire(sw) == null || si.getNetFromSiteWire(sw).isStaticNet())
-                                    continue;
-                                tfeat.add(name + "." + si.getSiteTypeEnum().toString() + "." + pinname + "INV." + v);
-                            } else if (propname.equals("COMPENSATION")) {
-                                tfeat.add(name +  "." + si.getSiteTypeEnum().toString() + "." + propname + "." + v);
-                            }
-                        }
-                    }
+                    tfeat.add("POD12_DCI_USED");
                 }
-                for (Tile t : des.getDevice().getAllTiles()) {
-                    if (t.getTileTypeEnum() != TileTypeEnum.RCLK_HPIO_L)
-                        continue;
-                    boolean dci_used = false;
-                    Tile[] io_tiles = {des.getDevice().getTile(t.getRow()+30, t.getColumn()), des.getDevice().getTile(t.getRow()-1, t.getColumn())};
-                    for (Tile iot : io_tiles) {
-                        for (Site s : iot.getSites()) {
-                            SiteInst si = des.getSiteInstFromSite(s);
-                            if (si == null)
-                                continue;
-                            Cell pad = si.getCell(si.getBEL("PAD"));
-                            if (pad == null)
-                                continue;
-                            EDIFPort p = des.getTopEDIFCell().getPort(pad.getName());
-                            if (des.getTopEDIFCell().getNet(pad.getName()) == null)
-                                continue;
-                            var prop = des.getTopEDIFCell().getNet(pad.getName()).getProperties();
-                            if (prop == null || !prop.containsKey(new EDIFName("IOSTANDARD")))
-                                continue;
-                            String iostd = prop.get(new EDIFName("IOSTANDARD")).getValue();
-                            if (iostd.contains("POD12_DCI") && !f.getName().contains("ipi")) // FIXME: find out why this loses bits
-                                dci_used = true;
-                        }
-                    }
-                    if (dci_used) {
-                        String tile = t.getName() + ":" + t.getTileTypeEnum().toString();
-                        if (!sitefeatures_by_tile.containsKey(tile))
-                            sitefeatures_by_tile.put(tile, new ArrayList<>());
-                        ArrayList<String> tfeat = sitefeatures_by_tile.get(tile);
-                        tfeat.add("POD12_DCI_USED");
-                    }
-                }
-                FileWriter vf = new FileWriter(f.getAbsolutePath().replace(".dcp", ".features"), false);
-                PrintWriter v = new PrintWriter(vf);
-                for (Tile t : des.getDevice().getAllTiles()) {
-                    TileTypeEnum tt = t.getTileTypeEnum();
-                    if (tt == TileTypeEnum.RCLK_INT_L|| tt == TileTypeEnum.RCLK_CLEM_L || tt == TileTypeEnum.RCLK_INT_R || tt == TileTypeEnum.RCLK_CLEM_CLKBUF_L || tt == TileTypeEnum.RCLK_CLEM_R ||
-                            tt == TileTypeEnum.RCLK_DSP_INTF_L || tt == TileTypeEnum.RCLK_BRAM_L || tt == TileTypeEnum.RCLK_BRAM_R || tt == TileTypeEnum.RCLK_BRAM_INTF_L ||
-                            tt == TileTypeEnum.RCLK_DSP_INTF_R || tt == TileTypeEnum.RCLK_DSP_CLKBUF_L || tt == TileTypeEnum.RCLK_RCLK_XIPHY_INNER_FT || tt == TileTypeEnum.RCLK_RCLK_INTF_XIPHY_LEFT_L_FT ||
-                            tt == TileTypeEnum.RCLK_HDIO || tt == TileTypeEnum.RCLK_HPIO_L || tt == TileTypeEnum.RCLK_HPIO_R ||
-                            tt == TileTypeEnum.RCLK_CLEL_L || tt == TileTypeEnum.RCLK_CLEL_R || tt == TileTypeEnum.RCLK_CLEL_L_L || tt == TileTypeEnum.RCLK_CLEL_L_R ||
-                            tt == TileTypeEnum.RCLK_DSP_INTF_CLKBUF_L || tt == TileTypeEnum.RCLK_BRAM_INTF_TD_L || tt == TileTypeEnum.RCLK_BRAM_INTF_TD_R || tt == TileTypeEnum.CMT_L || tt == TileTypeEnum.CMT_RIGHT ||
-                            tt == TileTypeEnum.RCLK_RCLK_URAM_INTF_L_FT || tt == TileTypeEnum.GTH_QUAD_RIGHT) {
-                        String tname = t.getName() + ":" + tt.toString();
-                        if (!pips_by_tile.containsKey(tname) && !sitefeatures_by_tile.containsKey(tname))
-                            continue;
-                        v.println(".tile " + tname);
-                        if (pips_by_tile.containsKey(tname))
-                            for (String p : pips_by_tile.get(tname))
-                                v.println(p);
-                        if (sitefeatures_by_tile.containsKey(tname))
-                            for (String sf : sitefeatures_by_tile.get(tname))
-                                v.println(sf);
-                    }
-                }
-                vf.close();
             }
+            FileWriter vf = new FileWriter(f.replace(".dcp", ".features"), false);
+            PrintWriter v = new PrintWriter(vf);
+            for (Tile t : des.getDevice().getAllTiles()) {
+                TileTypeEnum tt = t.getTileTypeEnum();
+                if (tt == TileTypeEnum.RCLK_INT_L|| tt == TileTypeEnum.RCLK_CLEM_L || tt == TileTypeEnum.RCLK_INT_R || tt == TileTypeEnum.RCLK_CLEM_CLKBUF_L || tt == TileTypeEnum.RCLK_CLEM_R ||
+                        tt == TileTypeEnum.RCLK_DSP_INTF_L || tt == TileTypeEnum.RCLK_BRAM_L || tt == TileTypeEnum.RCLK_BRAM_R || tt == TileTypeEnum.RCLK_BRAM_INTF_L ||
+                        tt == TileTypeEnum.RCLK_DSP_INTF_R || tt == TileTypeEnum.RCLK_DSP_CLKBUF_L || tt == TileTypeEnum.RCLK_RCLK_XIPHY_INNER_FT || tt == TileTypeEnum.RCLK_RCLK_INTF_XIPHY_LEFT_L_FT ||
+                        tt == TileTypeEnum.RCLK_HDIO || tt == TileTypeEnum.RCLK_HPIO_L || tt == TileTypeEnum.RCLK_HPIO_R ||
+                        tt == TileTypeEnum.RCLK_CLEL_L || tt == TileTypeEnum.RCLK_CLEL_R || tt == TileTypeEnum.RCLK_CLEL_L_L || tt == TileTypeEnum.RCLK_CLEL_L_R ||
+                        tt == TileTypeEnum.RCLK_DSP_INTF_CLKBUF_L || tt == TileTypeEnum.RCLK_BRAM_INTF_TD_L || tt == TileTypeEnum.RCLK_BRAM_INTF_TD_R || tt == TileTypeEnum.CMT_L || tt == TileTypeEnum.CMT_RIGHT ||
+                        tt == TileTypeEnum.RCLK_RCLK_URAM_INTF_L_FT || tt == TileTypeEnum.GTH_QUAD_RIGHT) {
+                    String tname = t.getName() + ":" + tt.toString();
+                    if (!pips_by_tile.containsKey(tname) && !sitefeatures_by_tile.containsKey(tname))
+                        continue;
+                    v.println(".tile " + tname);
+                    if (pips_by_tile.containsKey(tname))
+                        for (String p : pips_by_tile.get(tname))
+                            v.println(p);
+                    if (sitefeatures_by_tile.containsKey(tname))
+                        for (String sf : sitefeatures_by_tile.get(tname))
+                            v.println(sf);
+                }
+            }
+            vf.close();
         }
-
     }
 }
diff --git a/dump_features.java b/dump_features.java
index 56cfc11..4646846 100644
--- a/dump_features.java
+++ b/dump_features.java
@@ -12,15 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package dev.fpga.rapidwright;
-
 import com.xilinx.rapidwright.design.*;
 import com.xilinx.rapidwright.design.tools.LUTTools;
 import com.xilinx.rapidwright.device.*;
 import com.xilinx.rapidwright.edif.EDIFPortInst;
 import com.xilinx.rapidwright.edif.EDIFPropertyValue;
 import com.xilinx.rapidwright.edif.EDIFValueType;
-import jnr.ffi.annotations.In;
 import org.json.Property;
 
 import java.io.File;
@@ -73,337 +70,330 @@
     }
 
     public static void main(String[] args) throws IOException {
-
-
-        Scanner scanner = new Scanner(new File("/invpips.txt"));
+        Scanner scanner = new Scanner(new File("invpips.txt"));
         while (scanner.hasNextLine()) {
             String nl = scanner.nextLine().trim();
             inverted_pips.add(nl);
         }
 
-        File folder = new File("/specimen");
-        File[] listOfFiles = folder.listFiles();
-        for (File f : listOfFiles) {
-            if (f.getName().endsWith(".dcp")) {
-                Design des = Design.readCheckpoint(f.getAbsolutePath());
-                HashMap<String, ArrayList<String>> pips_by_tile = new HashMap<>();
-                HashMap<String, ArrayList<String>> sitefeatures_by_tile = new HashMap<>();
-                for (Net n : des.getNets()) {
+        for (String f : args) {
+            Design des = Design.readCheckpoint(f);
+            HashMap<String, ArrayList<String>> pips_by_tile = new HashMap<>();
+            HashMap<String, ArrayList<String>> sitefeatures_by_tile = new HashMap<>();
+            for (Net n : des.getNets()) {
 
-                    HashMap<Node, PIP> uphill = new HashMap<>();
-                    HashSet<Node> allnodes = new HashSet<>();
+                HashMap<Node, PIP> uphill = new HashMap<>();
+                HashSet<Node> allnodes = new HashSet<>();
 
-                    if (n.getSource() != null)
-                        uphill.put(n.getSource().getConnectedNode(), null);
-                    for (PIP p : n.getPIPs()) {
-                        uphill.put(p.getEndNode(), p);
-                        allnodes.add(p.getStartNode());
-                        allnodes.add(p.getEndNode());
-                    }
-
-                    for (Node node : allnodes) {
-                        for (Wire w : node.getAllWiresInNode()) {
-                            TileTypeEnum wtt = w.getTile().getTileTypeEnum();
-                            if (wtt == TileTypeEnum.RCLK_BRAM_INTF_L || wtt == TileTypeEnum.RCLK_BRAM_INTF_TD_L || wtt == TileTypeEnum.RCLK_BRAM_INTF_TD_R ||
-                                wtt == TileTypeEnum.RCLK_CLEL_L_L || wtt == TileTypeEnum.RCLK_CLEL_L || wtt == TileTypeEnum.RCLK_CLEL_L_R ||
-                                    wtt == TileTypeEnum.RCLK_CLEM_CLKBUF_L || wtt == TileTypeEnum.RCLK_CLEM_L || wtt == TileTypeEnum.RCLK_DSP_INTF_L) {
-                                if (w.getWireName().startsWith("CLK_TEST_BUF_SITE_") || w.getWireName().startsWith("CLK_HROUTE_CORE_OPT")) {
-                                    String tile = w.getTile().getName() + ":" + w.getTile().getTileTypeEnum().toString();
-                                    if (!pips_by_tile.containsKey(tile))
-                                        pips_by_tile.put(tile, new ArrayList<>());
-                                    pips_by_tile.get(tile).add("WIRE." + w.getWireName() + ".USED");
-
-                                }
-                            }
-                            if (wtt == TileTypeEnum.RCLK_DSP_INTF_CLKBUF_L || wtt == TileTypeEnum.RCLK_CLEM_CLKBUF_L || wtt == TileTypeEnum.RCLK_BRAM_INTF_L) {
-                                if (w.getWireName().startsWith("CLK_HROUTE") || w.getWireName().startsWith("CLK_HDISTR") ) {
-                                    String tile = w.getTile().getName() + ":" + w.getTile().getTileTypeEnum().toString();
-                                    if (!pips_by_tile.containsKey(tile))
-                                        pips_by_tile.put(tile, new ArrayList<>());
-                                    pips_by_tile.get(tile).add("WIRE." + w.getWireName() + ".USED");
-                                }
-                            }
-                        }
-                    }
-
-                    for (PIP p : n.getPIPs()) {
-
-                        String tile = p.getTile().getName() + ":" + p.getTile().getTileTypeEnum().toString();
-                        TileTypeEnum ptt = p.getTile().getTileTypeEnum();
-                        if (ptt == TileTypeEnum.BRAM)
-                            continue;
-                        if (!pips_by_tile.containsKey(tile))
-                            pips_by_tile.put(tile, new ArrayList<>());
-                        if (ptt == TileTypeEnum.INT_INTF_L_IO) {
-                            if (p.getEndWireName().contains("LOGIC_OUTS"))
-                                pips_by_tile.get(tile).add("WIRE.LOGIC_OUTS_R.DRIVEN");
-                            continue;
-                        }
-                        if (p.isBidirectional()) {
-                            boolean is_fwd = uphill.containsKey(p.getStartNode());
-                            pips_by_tile.get(tile).add("PIP." + p.getEndWireName() + "." + p.getStartWireName() + (is_fwd ? ".FWD" : ".REV"));
-                        } else {
-                            pips_by_tile.get(tile).add("PIP." + p.getEndWireName() + "." + p.getStartWireName());
-                        }
-                    }
+                if (n.getSource() != null)
+                    uphill.put(n.getSource().getConnectedNode(), null);
+                for (PIP p : n.getPIPs()) {
+                    uphill.put(p.getEndNode(), p);
+                    allnodes.add(p.getStartNode());
+                    allnodes.add(p.getEndNode());
                 }
-                for (SiteInst si : des.getSiteInsts()) {
-                    String tile = si.getTile().getName() + ":" + si.getTile().getTileTypeEnum().toString();
-                    if (!sitefeatures_by_tile.containsKey(tile))
-                        sitefeatures_by_tile.put(tile, new ArrayList<>());
-                    ArrayList<String> tfeat = sitefeatures_by_tile.get(tile);
-                    if (si.getSiteTypeEnum() == SiteTypeEnum.SLICEL || si.getSiteTypeEnum() == SiteTypeEnum.SLICEM) {
-                        boolean[] clkinv = {false, false}, srinv = {false, false}, ffsync = {false, false}, latch = {false, false};
-                        boolean[] haveff = {false, false};
-                        boolean[] srused = {false, false, false, false};
-                        boolean[] ceused = {false, false, false, false};
 
-                        for (BEL b : si.getBELs()) {
-                            String belName = b.getName();
-                            Cell c = si.getCell(b);
-                            if (c == null)
-                                continue;
+                for (Node node : allnodes) {
+                    for (Wire w : node.getAllWiresInNode()) {
+                        TileTypeEnum wtt = w.getTile().getTileTypeEnum();
+                        if (wtt == TileTypeEnum.RCLK_BRAM_INTF_L || wtt == TileTypeEnum.RCLK_BRAM_INTF_TD_L || wtt == TileTypeEnum.RCLK_BRAM_INTF_TD_R ||
+                            wtt == TileTypeEnum.RCLK_CLEL_L_L || wtt == TileTypeEnum.RCLK_CLEL_L || wtt == TileTypeEnum.RCLK_CLEL_L_R ||
+                                wtt == TileTypeEnum.RCLK_CLEM_CLKBUF_L || wtt == TileTypeEnum.RCLK_CLEM_L || wtt == TileTypeEnum.RCLK_DSP_INTF_L) {
+                            if (w.getWireName().startsWith("CLK_TEST_BUF_SITE_") || w.getWireName().startsWith("CLK_HROUTE_CORE_OPT")) {
+                                String tile = w.getTile().getName() + ":" + w.getTile().getTileTypeEnum().toString();
+                                if (!pips_by_tile.containsKey(tile))
+                                    pips_by_tile.put(tile, new ArrayList<>());
+                                pips_by_tile.get(tile).add("WIRE." + w.getWireName() + ".USED");
 
-                            if (belName.contains("LUT")) {
-                                if (c.getType().startsWith("RAM")) {
-                                    tfeat.add(belName.replaceAll("[56]", "") + ".RAM");
-                                    if (c.getType().contains("32"))
-                                        tfeat.add(belName.replaceAll("[56]", "") + ".RAM.SMALL");
-                                    else
-                                        tfeat.add(belName.replaceAll("[56]", "") + ".RAM.LARGE");
-                                }
-                                if (c.getType().contains("SRL"))
-                                    tfeat.add(belName.replaceAll("[56]", "") + ".SRL");
-                                if (c.getType().contains("SRL16"))
-                                    tfeat.add(belName.replaceAll("[56]", "") + ".SRL.SMALL");
-                                if (c.getType().contains("SRLC32"))
-                                    tfeat.add(belName.replaceAll("[56]", "") + ".SRL.LARGE");
-
-                                for (int i = 6; i <= 8; i++) {
-                                    if (c.getPhysicalPinMapping("WADR" + i) != null)
-                                        tfeat.add("WA" + (i+1) + "USED");
-                                }
-                                if (c.getType().contains("SRLC32") && c.getEDIFCellInst() != null) {
-                                    EDIFPortInst epi = c.getEDIFCellInst().getPortInst("D");
-                                    if (epi != null && c.getPhysicalPinMapping("D") != null)
-                                        tfeat.add(belName.replaceAll("[56]", "") + ".DI1." + c.getPhysicalPinMapping("D"));
-                                } else if (c.getLogicalPinMapping("DI1") != null) {
-                                    tfeat.add(belName.replaceAll("[56]", "") + ".DI1.DI1");
-                                }
-                                if ((c.getType().contains("RAM") || c.getType().contains("SRL")) && c.getEDIFCellInst() != null && c.getProperty("IS_CLK_INVERTED") != null) {
-                                    String lclkinv = c.getProperty("IS_CLK_INVERTED").getValue();
-                                    tfeat.add("LCLKINV." + lclkinv.substring(lclkinv.length() - 1));
-                                }
-
-                            }
-
-                            var p2l = c.getPinMappingsP2L();
-                            if (belName.contains("LUT") && c.getEDIFCellInst() != null && c.getProperty("INIT") != null) {
-                                boolean has_56lut = false;
-                                if (belName.contains("6LUT") && si.getCell(si.getBEL(belName.replace('6', '5'))) != null)
-                                    has_56lut = true;
-                                if (!has_56lut && (c.getType().startsWith("LUT"))) {
-                                    // LUT init bits
-                                    long long_init = LUTTools.getInitValue(c.getProperty("INIT").getValue());
-                                    for (int i = 0; i < 64; i++) {
-                                        if (belName.contains("5LUT") && (i >= 32))
-                                            continue;
-                                        String sw = belName.substring(0, 1) + "6";
-                                        Net sn = si.getNetFromSiteWire(sw);
-                                        if (belName.contains("6LUT") && sn != null && sn.getName().equals(Net.VCC_NET))
-                                            continue;
-                                        int init_index = 0;
-                                        boolean valid_index = true;
-                                        for (int j = 0; j < 6; j++) {
-                                            if ((i & (1 << j)) == 0)
-                                                continue;
-                                            String log = p2l.getOrDefault("A" + Integer.toString(j + 1), "");
-                                            if (log.isEmpty())
-                                                continue;
-                                            if (log.startsWith("RADR")) {
-                                                init_index |= (1 << (Integer.parseInt(log.substring(4))));
-                                            } else if (log.startsWith("A[")) {
-                                                init_index |= (1 << (Integer.parseInt(log.substring(2, 3))));
-                                            } else if (!log.startsWith("I") && !log.startsWith("A")) {
-                                                valid_index = false;
-                                                break;
-                                            } else {
-                                                init_index |= (1 << (Integer.parseInt(log.substring(1))));
-                                            }
-                                        }
-                                        if (!valid_index)
-                                            continue;
-                                        if ((long_init & (1L << init_index)) == 0)
-                                            continue;
-                                        tfeat.add(belName.replaceAll("[56]", "") + ".INIT[" + i + "]");
-                                    }
-                                }
-
-                            } else if (belName.contains("FF")) {
-                                boolean is_latch = false, is_sync = false, srval = false;
-                                String clkpin, srpin, cepin;
-                                if (c.getType().equals("FDPE")) {
-                                    is_latch = false;
-                                    is_sync = false;
-                                    srval = true;
-                                    clkpin = "C";
-                                    cepin = "CE";
-                                    srpin = "PRE";
-                                } else if (c.getType().equals("FDCE")) {
-                                    is_latch = false;
-                                    is_sync = false;
-                                    srval = false;
-                                    clkpin = "C";
-                                    cepin = "CE";
-                                    srpin = "CLR";
-                                } else if (c.getType().equals("FDSE")) {
-                                    is_latch = false;
-                                    is_sync = true;
-                                    srval = true;
-                                    clkpin = "C";
-                                    cepin = "CE";
-                                    srpin = "S";
-                                } else if (c.getType().equals("FDRE")) {
-                                    is_latch = false;
-                                    is_sync = true;
-                                    srval = false;
-                                    clkpin = "C";
-                                    cepin = "CE";
-                                    srpin = "R";
-                                } else if (c.getType().equals("LDPE")) {
-                                    is_latch = true;
-                                    is_sync = false;
-                                    srval = true;
-                                    clkpin = "G";
-                                    cepin = "GE";
-                                    srpin = "PRE";
-                                } else if (c.getType().equals("LDCE")) {
-                                    is_latch = true;
-                                    is_sync = false;
-                                    srval = false;
-                                    clkpin = "G";
-                                    cepin = "GE";
-                                    srpin = "CLR";
-                                } else {
-                                    continue;
-                                }
-                                String primtype = is_latch ? "LATCH" : "FF";
-                                if (c.getProperty("INIT") != null) {
-                                    String init = c.getProperty("INIT").getValue();
-                                    tfeat.add(belName + "." + primtype + ".INIT." + init.substring(init.length() - 1));
-                                }
-                                tfeat.add(belName + "." + primtype + ".SRVAL." + (srval ? "1" : "0"));
-                                int half = ("EFGH".contains(belName.substring(0, 1))) ? 1 : 0;
-                                latch[half] = is_latch;
-                                ffsync[half] = is_sync;
-                                clkinv[half] = (c.getProperty("IS_" + clkpin + "_INVERTED") != null && c.getProperty("IS_" + clkpin + "_INVERTED").getValue().equals("1'b1"));
-                                srinv[half] = (c.getProperty("IS_" + srpin + "_INVERTED") != null && c.getProperty("IS_" + srpin + "_INVERTED").getValue().equals("1'b1"));
-                                haveff[half] = true;
-                                int two = belName.endsWith("2") ? 1 : 0;
-                                srused[half * 2 + two] = (c.getPhysicalPinMapping(srpin) != null);
-                                ceused[half * 2 + two] = (c.getPhysicalPinMapping(cepin) != null);
-
-                            } else if (belName.contains("CARRY8")) {
-                                if (!c.getType().equals("CARRY8"))
-                                    continue;
-                                if (c.getProperty("CARRY_TYPE") != null)
-                                    tfeat.add("CARRY8.CARRY_TYPE." + c.getProperty("CARRY_TYPE").getValue());
-                                String[] pins = {"CI", "DI[0]", "DI[1]", "DI[2]", "DI[3]", "DI[4]", "DI[5]", "DI[6]", "DI[7]", "CI_TOP"};
-                                for (String p : pins) {
-                                    String phys = c.getPhysicalPinMapping(p);
-                                    if (phys != null && (!p.equals("CI") || !phys.equals("CIN"))) {
-                                        EDIFPortInst epi = c.getEDIFCellInst().getPortInst(p);
-                                        if (epi != null && epi.getNet() != null) {
-                                            String pn = p.replace("[", "").replace("]", "");
-                                            tfeat.add("CARRY8." + pn + "." + phys);
-                                        }
-                                    } else if (p.equals("CI") || p.equals("CI_TOP")) {
-                                        EDIFPortInst epi = c.getEDIFCellInst().getPortInst(p);
-                                        if (epi != null && epi.getNet() != null) {
-                                            String netname = epi.getNet().getName();
-                                            if (netname.equals("<const0>"))
-                                                tfeat.add("CARRY8." + p + ".0");
-                                            else if (netname.equals("<const1>"))
-                                                tfeat.add("CARRY8." + p + ".1");
-                                        }
-                                    }
-                                }
-                            }
-
-                        }
-                        for (int i = 0; i < 2; i++) {
-                            String half = "ABCDEFGH".substring(4 * i, 4 * (i + 1));
-                            if (!haveff[i])
-                                continue;
-                            String primtype = latch[i] ? "LATCH" : "FF";
-                            tfeat.add(half + "FF." + primtype);
-                            tfeat.add(half + "FF." + primtype + ".CLKINV." + (clkinv[i] ? "1" : "0"));
-                            tfeat.add(half + "FF." + primtype + ".SRINV." + (srinv[i] ? "1" : "0"));
-                            if (ffsync[i])
-                                tfeat.add(half + "FF." + primtype + ".SYNC");
-                            for (int j = 0; j < 2; j++) {
-                                if (srused[i * 2 + j])
-                                    tfeat.add(half + "FF" + (j == 1 ? "2" : "") + ".SRUSED");
-                                if (ceused[i * 2 + j])
-                                    tfeat.add(half + "FF" + (j == 1 ? "2" : "") + ".CEUSED");
                             }
                         }
-                        for (SitePIP sp : si.getUsedSitePIPs()) {
-                            if (sp.getBELName().contains("INV"))
-                                continue;
-                            if (sp.getBELName().startsWith("OUTMUX") && sp.getInputPinName().equals("D6")) {
-                                if (si.getSitePinInst(sp.getOutputPin().getConnectedSitePinName()) == null)
-                                    continue;
-                            }
-                            tfeat.add(sp.getBELName() + "." + sp.getInputPinName());
-                        }
-                    } else if (si.getSiteTypeEnum() == SiteTypeEnum.BUFCE_LEAF) {
-                        String name = site_index_in_tile(si.getTile(), si.getSite());
-                        for (Cell c : si.getCells()) {
-                            if (c.getType() != null && c.getType().equals("BUFCE_LEAF")) {
-                                tfeat.add(name + ".BUFCE_LEAF.IN_USE");
-                                if (c.getProperty("CE_TYPE") != null)
-                                    tfeat.add(name + ".BUFCE_LEAF.CE_TYPE." + c.getProperty("CE_TYPE").getValue());
-                                var all_props = c.getProperties();
-                                for (var e : all_props.entrySet()) {
-                                    String propname = e.getKey().getName();
-                                    if (propname.startsWith("IS_") && propname.endsWith("_INVERTED")) {
-                                        String pinname = propname.substring(3, propname.length() - 9);
-                                        String v = e.getValue().getValue();
-                                        int base_pos = v.indexOf("'b");
-                                        if (base_pos != -1)
-                                            v = v.substring(base_pos + 2);
-                                        if (pinname.equals("I"))
-                                            if (is_sink_inverted(si.getSitePinInst("CLK_IN")))
-                                                v = (v.equals("1") ? "0" : "1");
-                                        tfeat.add(name + ".BUFCE_LEAF." + pinname + "INV." + v);
-                                    }
-                                }
+                        if (wtt == TileTypeEnum.RCLK_DSP_INTF_CLKBUF_L || wtt == TileTypeEnum.RCLK_CLEM_CLKBUF_L || wtt == TileTypeEnum.RCLK_BRAM_INTF_L) {
+                            if (w.getWireName().startsWith("CLK_HROUTE") || w.getWireName().startsWith("CLK_HDISTR") ) {
+                                String tile = w.getTile().getName() + ":" + w.getTile().getTileTypeEnum().toString();
+                                if (!pips_by_tile.containsKey(tile))
+                                    pips_by_tile.put(tile, new ArrayList<>());
+                                pips_by_tile.get(tile).add("WIRE." + w.getWireName() + ".USED");
                             }
                         }
                     }
                 }
-                FileWriter vf = new FileWriter(f.getAbsolutePath().replace(".dcp", ".features"), false);
-                PrintWriter v = new PrintWriter(vf);
-                for (Tile t : des.getDevice().getAllTiles()) {
-                    TileTypeEnum tt = t.getTileTypeEnum();
-                    if (tt == TileTypeEnum.CLEL_L || tt == TileTypeEnum.CLEL_R || tt == TileTypeEnum.CLEM_R || tt == TileTypeEnum.CLEM
-                            || tt == TileTypeEnum.INT || tt == TileTypeEnum.INT_INTF_L_IO) {
-                        String tname = t.getName() + ":" + tt.toString();
-                        if (!pips_by_tile.containsKey(tname) && !sitefeatures_by_tile.containsKey(tname))
-                            continue;
-                        v.println(".tile " + tname);
-                        if (pips_by_tile.containsKey(tname))
-                            for (String p : pips_by_tile.get(tname))
-                                v.println(p);
-                        if (sitefeatures_by_tile.containsKey(tname))
-                            for (String sf : sitefeatures_by_tile.get(tname))
-                                v.println(sf);
+
+                for (PIP p : n.getPIPs()) {
+
+                    String tile = p.getTile().getName() + ":" + p.getTile().getTileTypeEnum().toString();
+                    TileTypeEnum ptt = p.getTile().getTileTypeEnum();
+                    if (ptt == TileTypeEnum.BRAM)
+                        continue;
+                    if (!pips_by_tile.containsKey(tile))
+                        pips_by_tile.put(tile, new ArrayList<>());
+                    if (ptt == TileTypeEnum.INT_INTF_L_IO) {
+                        if (p.getEndWireName().contains("LOGIC_OUTS"))
+                            pips_by_tile.get(tile).add("WIRE.LOGIC_OUTS_R.DRIVEN");
+                        continue;
+                    }
+                    if (p.isBidirectional()) {
+                        boolean is_fwd = uphill.containsKey(p.getStartNode());
+                        pips_by_tile.get(tile).add("PIP." + p.getEndWireName() + "." + p.getStartWireName() + (is_fwd ? ".FWD" : ".REV"));
+                    } else {
+                        pips_by_tile.get(tile).add("PIP." + p.getEndWireName() + "." + p.getStartWireName());
                     }
                 }
-                vf.close();
             }
-        }
+            for (SiteInst si : des.getSiteInsts()) {
+                String tile = si.getTile().getName() + ":" + si.getTile().getTileTypeEnum().toString();
+                if (!sitefeatures_by_tile.containsKey(tile))
+                    sitefeatures_by_tile.put(tile, new ArrayList<>());
+                ArrayList<String> tfeat = sitefeatures_by_tile.get(tile);
+                if (si.getSiteTypeEnum() == SiteTypeEnum.SLICEL || si.getSiteTypeEnum() == SiteTypeEnum.SLICEM) {
+                    boolean[] clkinv = {false, false}, srinv = {false, false}, ffsync = {false, false}, latch = {false, false};
+                    boolean[] haveff = {false, false};
+                    boolean[] srused = {false, false, false, false};
+                    boolean[] ceused = {false, false, false, false};
 
+                    for (BEL b : si.getBELs()) {
+                        String belName = b.getName();
+                        Cell c = si.getCell(b);
+                        if (c == null)
+                            continue;
+
+                        if (belName.contains("LUT")) {
+                            if (c.getType().startsWith("RAM")) {
+                                tfeat.add(belName.replaceAll("[56]", "") + ".RAM");
+                                if (c.getType().contains("32"))
+                                    tfeat.add(belName.replaceAll("[56]", "") + ".RAM.SMALL");
+                                else
+                                    tfeat.add(belName.replaceAll("[56]", "") + ".RAM.LARGE");
+                            }
+                            if (c.getType().contains("SRL"))
+                                tfeat.add(belName.replaceAll("[56]", "") + ".SRL");
+                            if (c.getType().contains("SRL16"))
+                                tfeat.add(belName.replaceAll("[56]", "") + ".SRL.SMALL");
+                            if (c.getType().contains("SRLC32"))
+                                tfeat.add(belName.replaceAll("[56]", "") + ".SRL.LARGE");
+
+                            for (int i = 6; i <= 8; i++) {
+                                if (c.getPhysicalPinMapping("WADR" + i) != null)
+                                    tfeat.add("WA" + (i+1) + "USED");
+                            }
+                            if (c.getType().contains("SRLC32") && c.getEDIFCellInst() != null) {
+                                EDIFPortInst epi = c.getEDIFCellInst().getPortInst("D");
+                                if (epi != null && c.getPhysicalPinMapping("D") != null)
+                                    tfeat.add(belName.replaceAll("[56]", "") + ".DI1." + c.getPhysicalPinMapping("D"));
+                            } else if (c.getLogicalPinMapping("DI1") != null) {
+                                tfeat.add(belName.replaceAll("[56]", "") + ".DI1.DI1");
+                            }
+                            if ((c.getType().contains("RAM") || c.getType().contains("SRL")) && c.getEDIFCellInst() != null && c.getProperty("IS_CLK_INVERTED") != null) {
+                                String lclkinv = c.getProperty("IS_CLK_INVERTED").getValue();
+                                tfeat.add("LCLKINV." + lclkinv.substring(lclkinv.length() - 1));
+                            }
+
+                        }
+
+                        var p2l = c.getPinMappingsP2L();
+                        if (belName.contains("LUT") && c.getEDIFCellInst() != null && c.getProperty("INIT") != null) {
+                            boolean has_56lut = false;
+                            if (belName.contains("6LUT") && si.getCell(si.getBEL(belName.replace('6', '5'))) != null)
+                                has_56lut = true;
+                            if (!has_56lut && (c.getType().startsWith("LUT"))) {
+                                // LUT init bits
+                                long long_init = LUTTools.getInitValue(c.getProperty("INIT").getValue());
+                                for (int i = 0; i < 64; i++) {
+                                    if (belName.contains("5LUT") && (i >= 32))
+                                        continue;
+                                    String sw = belName.substring(0, 1) + "6";
+                                    Net sn = si.getNetFromSiteWire(sw);
+                                    if (belName.contains("6LUT") && sn != null && sn.getName().equals(Net.VCC_NET))
+                                        continue;
+                                    int init_index = 0;
+                                    boolean valid_index = true;
+                                    for (int j = 0; j < 6; j++) {
+                                        if ((i & (1 << j)) == 0)
+                                            continue;
+                                        String log = p2l.getOrDefault("A" + Integer.toString(j + 1), "");
+                                        if (log.isEmpty())
+                                            continue;
+                                        if (log.startsWith("RADR")) {
+                                            init_index |= (1 << (Integer.parseInt(log.substring(4))));
+                                        } else if (log.startsWith("A[")) {
+                                            init_index |= (1 << (Integer.parseInt(log.substring(2, 3))));
+                                        } else if (!log.startsWith("I") && !log.startsWith("A")) {
+                                            valid_index = false;
+                                            break;
+                                        } else {
+                                            init_index |= (1 << (Integer.parseInt(log.substring(1))));
+                                        }
+                                    }
+                                    if (!valid_index)
+                                        continue;
+                                    if ((long_init & (1L << init_index)) == 0)
+                                        continue;
+                                    tfeat.add(belName.replaceAll("[56]", "") + ".INIT[" + i + "]");
+                                }
+                            }
+
+                        } else if (belName.contains("FF")) {
+                            boolean is_latch = false, is_sync = false, srval = false;
+                            String clkpin, srpin, cepin;
+                            if (c.getType().equals("FDPE")) {
+                                is_latch = false;
+                                is_sync = false;
+                                srval = true;
+                                clkpin = "C";
+                                cepin = "CE";
+                                srpin = "PRE";
+                            } else if (c.getType().equals("FDCE")) {
+                                is_latch = false;
+                                is_sync = false;
+                                srval = false;
+                                clkpin = "C";
+                                cepin = "CE";
+                                srpin = "CLR";
+                            } else if (c.getType().equals("FDSE")) {
+                                is_latch = false;
+                                is_sync = true;
+                                srval = true;
+                                clkpin = "C";
+                                cepin = "CE";
+                                srpin = "S";
+                            } else if (c.getType().equals("FDRE")) {
+                                is_latch = false;
+                                is_sync = true;
+                                srval = false;
+                                clkpin = "C";
+                                cepin = "CE";
+                                srpin = "R";
+                            } else if (c.getType().equals("LDPE")) {
+                                is_latch = true;
+                                is_sync = false;
+                                srval = true;
+                                clkpin = "G";
+                                cepin = "GE";
+                                srpin = "PRE";
+                            } else if (c.getType().equals("LDCE")) {
+                                is_latch = true;
+                                is_sync = false;
+                                srval = false;
+                                clkpin = "G";
+                                cepin = "GE";
+                                srpin = "CLR";
+                            } else {
+                                continue;
+                            }
+                            String primtype = is_latch ? "LATCH" : "FF";
+                            if (c.getProperty("INIT") != null) {
+                                String init = c.getProperty("INIT").getValue();
+                                tfeat.add(belName + "." + primtype + ".INIT." + init.substring(init.length() - 1));
+                            }
+                            tfeat.add(belName + "." + primtype + ".SRVAL." + (srval ? "1" : "0"));
+                            int half = ("EFGH".contains(belName.substring(0, 1))) ? 1 : 0;
+                            latch[half] = is_latch;
+                            ffsync[half] = is_sync;
+                            clkinv[half] = (c.getProperty("IS_" + clkpin + "_INVERTED") != null && c.getProperty("IS_" + clkpin + "_INVERTED").getValue().equals("1'b1"));
+                            srinv[half] = (c.getProperty("IS_" + srpin + "_INVERTED") != null && c.getProperty("IS_" + srpin + "_INVERTED").getValue().equals("1'b1"));
+                            haveff[half] = true;
+                            int two = belName.endsWith("2") ? 1 : 0;
+                            srused[half * 2 + two] = (c.getPhysicalPinMapping(srpin) != null);
+                            ceused[half * 2 + two] = (c.getPhysicalPinMapping(cepin) != null);
+
+                        } else if (belName.contains("CARRY8")) {
+                            if (!c.getType().equals("CARRY8"))
+                                continue;
+                            if (c.getProperty("CARRY_TYPE") != null)
+                                tfeat.add("CARRY8.CARRY_TYPE." + c.getProperty("CARRY_TYPE").getValue());
+                            String[] pins = {"CI", "DI[0]", "DI[1]", "DI[2]", "DI[3]", "DI[4]", "DI[5]", "DI[6]", "DI[7]", "CI_TOP"};
+                            for (String p : pins) {
+                                String phys = c.getPhysicalPinMapping(p);
+                                if (phys != null && (!p.equals("CI") || !phys.equals("CIN"))) {
+                                    EDIFPortInst epi = c.getEDIFCellInst().getPortInst(p);
+                                    if (epi != null && epi.getNet() != null) {
+                                        String pn = p.replace("[", "").replace("]", "");
+                                        tfeat.add("CARRY8." + pn + "." + phys);
+                                    }
+                                } else if (p.equals("CI") || p.equals("CI_TOP")) {
+                                    EDIFPortInst epi = c.getEDIFCellInst().getPortInst(p);
+                                    if (epi != null && epi.getNet() != null) {
+                                        String netname = epi.getNet().getName();
+                                        if (netname.equals("<const0>"))
+                                            tfeat.add("CARRY8." + p + ".0");
+                                        else if (netname.equals("<const1>"))
+                                            tfeat.add("CARRY8." + p + ".1");
+                                    }
+                                }
+                            }
+                        }
+
+                    }
+                    for (int i = 0; i < 2; i++) {
+                        String half = "ABCDEFGH".substring(4 * i, 4 * (i + 1));
+                        if (!haveff[i])
+                            continue;
+                        String primtype = latch[i] ? "LATCH" : "FF";
+                        tfeat.add(half + "FF." + primtype);
+                        tfeat.add(half + "FF." + primtype + ".CLKINV." + (clkinv[i] ? "1" : "0"));
+                        tfeat.add(half + "FF." + primtype + ".SRINV." + (srinv[i] ? "1" : "0"));
+                        if (ffsync[i])
+                            tfeat.add(half + "FF." + primtype + ".SYNC");
+                        for (int j = 0; j < 2; j++) {
+                            if (srused[i * 2 + j])
+                                tfeat.add(half + "FF" + (j == 1 ? "2" : "") + ".SRUSED");
+                            if (ceused[i * 2 + j])
+                                tfeat.add(half + "FF" + (j == 1 ? "2" : "") + ".CEUSED");
+                        }
+                    }
+                    for (SitePIP sp : si.getUsedSitePIPs()) {
+                        if (sp.getBELName().contains("INV"))
+                            continue;
+                        if (sp.getBELName().startsWith("OUTMUX") && sp.getInputPinName().equals("D6")) {
+                            if (si.getSitePinInst(sp.getOutputPin().getConnectedSitePinName()) == null)
+                                continue;
+                        }
+                        tfeat.add(sp.getBELName() + "." + sp.getInputPinName());
+                    }
+                } else if (si.getSiteTypeEnum() == SiteTypeEnum.BUFCE_LEAF) {
+                    String name = site_index_in_tile(si.getTile(), si.getSite());
+                    for (Cell c : si.getCells()) {
+                        if (c.getType() != null && c.getType().equals("BUFCE_LEAF")) {
+                            tfeat.add(name + ".BUFCE_LEAF.IN_USE");
+                            if (c.getProperty("CE_TYPE") != null)
+                                tfeat.add(name + ".BUFCE_LEAF.CE_TYPE." + c.getProperty("CE_TYPE").getValue());
+                            var all_props = c.getProperties();
+                            for (var e : all_props.entrySet()) {
+                                String propname = e.getKey().getName();
+                                if (propname.startsWith("IS_") && propname.endsWith("_INVERTED")) {
+                                    String pinname = propname.substring(3, propname.length() - 9);
+                                    String v = e.getValue().getValue();
+                                    int base_pos = v.indexOf("'b");
+                                    if (base_pos != -1)
+                                        v = v.substring(base_pos + 2);
+                                    if (pinname.equals("I"))
+                                        if (is_sink_inverted(si.getSitePinInst("CLK_IN")))
+                                            v = (v.equals("1") ? "0" : "1");
+                                    tfeat.add(name + ".BUFCE_LEAF." + pinname + "INV." + v);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            FileWriter vf = new FileWriter(f.replace(".dcp", ".features"), false);
+            PrintWriter v = new PrintWriter(vf);
+            for (Tile t : des.getDevice().getAllTiles()) {
+                TileTypeEnum tt = t.getTileTypeEnum();
+                if (tt == TileTypeEnum.CLEL_L || tt == TileTypeEnum.CLEL_R || tt == TileTypeEnum.CLEM_R || tt == TileTypeEnum.CLEM
+                        || tt == TileTypeEnum.INT || tt == TileTypeEnum.INT_INTF_L_IO) {
+                    String tname = t.getName() + ":" + tt.toString();
+                    if (!pips_by_tile.containsKey(tname) && !sitefeatures_by_tile.containsKey(tname))
+                        continue;
+                    v.println(".tile " + tname);
+                    if (pips_by_tile.containsKey(tname))
+                        for (String p : pips_by_tile.get(tname))
+                            v.println(p);
+                    if (sitefeatures_by_tile.containsKey(tname))
+                        for (String sf : sitefeatures_by_tile.get(tname))
+                            v.println(sf);
+                }
+            }
+            vf.close();
+        }
     }
 }