| // Copyright 2020 Project U-Ray Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // 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; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.io.PrintWriter; |
| import java.math.BigInteger; |
| import java.util.*; |
| |
| public class dump_features { |
| |
| static String site_index_in_tile(Tile t, Site s) { |
| int min_x = s.getInstanceX(), min_y = s.getInstanceY(); |
| for (Site s2 : t.getSites()) { |
| if (s2.getSiteTypeEnum() == s.getSiteTypeEnum()) { |
| min_x = Math.min(min_x, s2.getInstanceX()); |
| min_y = Math.min(min_y, s2.getInstanceY()); |
| } |
| } |
| return s.getSiteTypeEnum().toString() + "_X" + (s.getInstanceX() - min_x) + "Y" + (s.getInstanceY() - min_y); |
| } |
| |
| static HashSet<String> inverted_pips = new HashSet<>(); |
| |
| static boolean is_sink_inverted(SitePinInst spi) { |
| if (spi == null || spi.getNet() == null) |
| return false; |
| Net n = spi.getNet(); |
| HashMap<Node, PIP> pip_uphill = new HashMap<>(); |
| for (PIP p : n.getPIPs()) { |
| pip_uphill.putIfAbsent(p.getEndNode(), p); |
| if (p.isBidirectional()) { |
| pip_uphill.putIfAbsent(p.getStartNode(), p); |
| } |
| } |
| boolean inv = false; |
| Node cursor = spi.getConnectedNode(); |
| while (pip_uphill.containsKey(cursor)) { |
| PIP p = pip_uphill.get(cursor); |
| String name = p.getTile().getName() + "/" + p.getTile().getTileTypeEnum().toString() + "." + p.getStartWireName() + (p.isBidirectional() ? "<<->>" : "->>") + p.getEndWireName(); |
| if (inverted_pips.contains(name)) |
| inv = !inv; |
| //System.out.println(name + " " + inv); |
| if (p.isBidirectional() && p.getStartNode().equals(cursor)) |
| cursor = p.getEndNode(); |
| else |
| cursor = p.getStartNode(); |
| } |
| return inv; |
| } |
| |
| public static void main(String[] args) throws IOException { |
| |
| |
| 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()) { |
| |
| 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()); |
| } |
| } |
| } |
| 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.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); |
| } |
| } |
| vf.close(); |
| } |
| } |
| |
| } |
| } |