Java tutorial
/* * Copyright (c) 2016 Brigham Young University * * This file is part of the BYU RapidSmith Tools. * * BYU RapidSmith Tools is free software: you may redistribute it * and/or modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * BYU RapidSmith Tools is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * A copy of the GNU General Public License is included with the BYU * RapidSmith Tools. It can be found at doc/LICENSE.GPL3.TXT. You may * also get a copy of the license at <http://www.gnu.org/licenses/>. */ package edu.byu.ece.rapidSmith.device.creation; import edu.byu.ece.rapidSmith.RSEnvironment; import edu.byu.ece.rapidSmith.device.*; import edu.byu.ece.rapidSmith.device.xdlrc.XDLRCParseProgressListener; import edu.byu.ece.rapidSmith.device.xdlrc.XDLRCParserListener; import edu.byu.ece.rapidSmith.device.xdlrc.XDLRCSource; import edu.byu.ece.rapidSmith.primitiveDefs.*; import edu.byu.ece.rapidSmith.util.Exceptions; import edu.byu.ece.rapidSmith.util.HashPool; import edu.byu.ece.rapidSmith.util.PartNameTools; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.JDOMException; import java.io.IOException; import java.util.*; import java.util.stream.Collectors; import static edu.byu.ece.rapidSmith.util.Exceptions.EnvironmentException; import static edu.byu.ece.rapidSmith.util.Exceptions.FileFormatException; /** * Generates a new device through parsing the device's XDLRC representation. * <p> * Steps * 1) First parse * a) WireEnumeratorListener * i) Extract wire names, types, and directions from XDLRC * ii) Enumerate each wire name in device * b) TileAndPrimitiveSiteListener * i) Extract part name from XDLRC * ii) Extract number of rows and columns from XDLRC * iii) Construct device tile array * iv) Extract tile names and types * v) Create list of sites in each tile * vi) Extract name and type of each primitive site * vii) Define alternative types for each primitive site * c) PrimitiveDefsListener * i) Construct primitive defs structure * 2) Construct dependent resources * a) Build tile and sites name map * 2) Second parse * a) Build wire connection for each tile. Preserve all connections that * are either sources or sinks of a site or a PIP */ public final class DeviceGenerator { private Device device; private WireEnumerator we; private Document familyInfo; private static final int PIP_CAPACITY = 40000; private final Set<String> pipSources = new HashSet<>(PIP_CAPACITY); private final Set<String> pipSinks = new HashSet<>(PIP_CAPACITY); /** Keeps track of each unique Wire object in the device */ private HashPool<WireConnection> wirePool; /** Keeps track of each unique Wire[] object in the device */ private HashPool<WireArray> wireArrayPool; /** Keeps track of all PIPRouteThrough objects */ private HashPool<PIPRouteThrough> routeThroughPool; /** Keeps Track of all unique Wire Lists that exist in Tiles */ private HashPool<WireHashMap> tileWiresPool; private HashPool<Map<String, Integer>> externalWiresPool; private HashPool<Map<SiteType, Map<String, Integer>>> externalWiresMapPool; private HashPool<AlternativeTypes> alternativeTypesPool; private Set<Integer> siteWireSourceSet; private Set<Integer> siteWireSinkSet; /** * Generates and returns the Device created from the XDLRC at the specified * source. * * @param xdlrcSource the XDLRC source containing the device description * @return the generated Device representation */ public Device generate(XDLRCSource xdlrcSource) throws IOException { System.out.println("Generating device for file " + xdlrcSource.getFilePath()); this.device = new Device(); this.we = new WireEnumerator(); this.device.setWireEnumerator(we); this.wirePool = new HashPool<>(); this.wireArrayPool = new HashPool<>(); this.routeThroughPool = new HashPool<>(); this.tileWiresPool = new HashPool<>(); this.externalWiresPool = new HashPool<>(); this.externalWiresMapPool = new HashPool<>(); this.alternativeTypesPool = new HashPool<>(); // Requires a two part iteration, the first to obtain the tiles and sites, // and the second to gather the wires. Two parses are required since the // wires need to know the source and sink tiles. System.out.println("Starting first pass"); xdlrcSource.registerListener(new FamilyTypeListener()); xdlrcSource.registerListener(new WireEnumeratorListener()); xdlrcSource.registerListener(new TileAndSiteGeneratorListener()); xdlrcSource.registerListener(new PrimitiveDefsListener()); xdlrcSource.registerListener(new XDLRCParseProgressListener()); try { xdlrcSource.parse(); } catch (IOException e) { throw new IOException("Error handling file " + xdlrcSource.getFilePath(), e); } xdlrcSource.clearListeners(); device.constructTileMap(); PrimitiveDefsCorrector.makeCorrections(device.getPrimitiveDefs(), familyInfo); device.setSiteTemplates(createSiteTemplates()); System.out.println("Starting second pass"); xdlrcSource.registerListener(new WireConnectionGeneratorListener()); xdlrcSource.registerListener(new ReverseWireConnectionGeneratorListener()); xdlrcSource.registerListener(new SourceAndSinkListener()); xdlrcSource.registerListener(new XDLRCParseProgressListener()); try { xdlrcSource.parse(); } catch (IOException e) { throw new IOException("Error handling file " + xdlrcSource.getFilePath(), e); } Map<Tile, Map<Integer, Set<WireConnection>>> wcsToAdd = getWCsToAdd(true); Map<Tile, Map<Integer, Set<WireConnection>>> wcsToRemove = getWCsToRemove(true); Map<Tile, Map<Integer, Set<WireConnection>>> revwcsToAdd = getWCsToAdd(false); Map<Tile, Map<Integer, Set<WireConnection>>> revwcsToRemove = getWCsToRemove(false); // These take up a lot of memory and we're going to regenerate each of these in the // next step. Clearing these will allow for better garbage collection wirePool = new HashPool<>(); wireArrayPool = new HashPool<>(); tileWiresPool = new HashPool<>(); System.out.println("Parsing Device Info file"); if (!parseDeviceInfo(device)) { System.err.println( "[Warning]: The device info file for the part " + device.getPartName() + " cannot be found."); } makeWireCorrections(wcsToAdd, wcsToRemove, true); makeWireCorrections(revwcsToAdd, revwcsToRemove, false); device.constructDependentResources(); // free unneeded pools for garbage collection when done with routeThroughPool = null; System.out.println("Finishing device creation process"); return device; } /** * Creates the templates for the primitive sites with information from the * primitive defs and device information file. */ private Map<SiteType, SiteTemplate> createSiteTemplates() { Map<SiteType, SiteTemplate> siteTemplates = new HashMap<>(); FamilyType family = device.getFamily(); // Create a template for each primitive type for (PrimitiveDef def : device.getPrimitiveDefs()) { Element ptEl = getSiteTypeEl(def.getType()); SiteTemplate template = new SiteTemplate(); template.setType(def.getType()); template.setBelTemplates(createBelTemplates(def, ptEl)); createAndSetIntrasiteRouting(def, template, ptEl); createAndSetSitePins(def, template); Element compatTypesEl = ptEl.getChild("compatible_types"); if (compatTypesEl != null) { template.setCompatibleTypes(compatTypesEl.getChildren("compatible_type").stream() .map(it -> SiteType.valueOf(family, it.getText())).toArray(SiteType[]::new)); } siteTemplates.put(def.getType(), template); } return siteTemplates; } /** * Creates the templates for each BEL in the primitive site * * @param def The primitive def to process * @param ptElement XML element detailing the primitive type * @return The templates for each BEL in the primitive type */ private Map<String, BelTemplate> createBelTemplates(PrimitiveDef def, Element ptElement) { Map<String, BelTemplate> templates = new HashMap<>(); // for each BEL element for (PrimitiveElement el : def.getElements()) { if (!el.isBel()) continue; BelId id = new BelId(def.getType(), el.getName()); // Set the BEL type as defined in the deviceinfo file String belType = getTypeOfBel(el.getName(), ptElement); BelTemplate template = new BelTemplate(id, belType); // Create the BEL pin templates Map<String, BelPinTemplate> sinks = new HashMap<>(); Map<String, BelPinTemplate> sources = new HashMap<>(); for (PrimitiveDefPin pin : el.getPins()) { BelPinTemplate belPin = new BelPinTemplate(id, pin.getInternalName()); belPin.setDirection(pin.getDirection()); String wireName = getIntrasiteWireName(def.getType(), el.getName(), belPin.getName()); belPin.setWire(we.getWireEnum(wireName)); if (pin.getDirection() == PinDirection.IN || pin.getDirection() == PinDirection.INOUT) sinks.put(belPin.getName(), belPin); if (pin.getDirection() == PinDirection.OUT || pin.getDirection() == PinDirection.INOUT) sources.put(belPin.getName(), belPin); } template.setSources(sources); template.setSinks(sinks); templates.put(el.getName(), template); } // Find the site pins that connect to each BEL pin by traversing the routing. // This info is useful for directing which site pin should be targeted while // routing to reach the correct BEL pin. for (PrimitiveDefPin pin : def.getPins()) { PrimitiveElement el = def.getElement(pin.getInternalName()); boolean forward = !pin.isOutput(); // traverse forward or backward? findAndSetSitePins(def, forward, el); } return templates; } /** * Recursively traverses through the elements to find all BEL pins reachable from the site pin. * * @param def the primitive def for the current type * @param forward traverse forward or backward (forward for site sinks and * backward for site sources) * @param element The current element we're looking at */ private void findAndSetSitePins(PrimitiveDef def, boolean forward, PrimitiveElement element) { // follow each connection from the element for (PrimitiveConnection c : element.getConnections()) { PrimitiveElement destElement; // This connection goes the opposite of the way we want to search if (forward != c.isForwardConnection()) continue; destElement = def.getElement(c.getElement1()); if (destElement.isMux()) { // This is a routing mux. Follow it. findAndSetSitePins(def, forward, destElement); } } } /** * Find the XML element specifying the type for the desired BEL * * @param belName name of the BEL to find the type for * @param ptElement XML element detailing the primitive type * @return the BEL type */ private String getTypeOfBel(String belName, Element ptElement) { for (Element belEl : ptElement.getChild("bels").getChildren("bel")) { if (belEl.getChildText("name").equals(belName)) return belEl.getChildText("type"); } assert false : "No type found for the specified BEL " + belName + " " + ptElement.getChildText("name"); return null; } /** * Creates the wire connections connecting the BELs and muxes in the primitive type. * * @param def the primitive def for the current type * @param template the template for the current type */ private void createAndSetIntrasiteRouting(PrimitiveDef def, SiteTemplate template, Element siteElement) { WireHashMap forwardWireMap = new WireHashMap(); WireHashMap reverseWireMap = new WireHashMap(); /* We build the routing structure by find all of the wire sources and creating a wire connection between it and its sinks. For muxes, we additionally create a wire connection from each input of the mux to the output. */ for (PrimitiveElement el : def.getElements()) { String elName = el.getName(); if (el.isPin() && !def.getPin(elName).isOutput()) { // input site pin addWireConnectionsForElement(def, el, forwardWireMap, reverseWireMap); } else if (el.isBel()) { addWireConnectionsForElement(def, el, forwardWireMap, reverseWireMap); } else if (el.isMux()) { addWireConnectionsForElement(def, el, forwardWireMap, reverseWireMap); createAndAddMuxPips(def, el, forwardWireMap, reverseWireMap); } } Map<Integer, Set<Integer>> belRoutethroughMap = createBelRoutethroughs(template, siteElement, forwardWireMap, reverseWireMap); template.setBelRoutethroughs(belRoutethroughMap); template.setRouting(forwardWireMap); template.setReverseRouting(reverseWireMap); } /** * Creates a BEL routethrough map for the site template. * @param template Site Template to generate routethroughs for * @param siteElement XML document element of the site in the familyinfo.xml file * @param wireMap WireHashMap of the site template * @return A Map of BEL routethroughs */ private Map<Integer, Set<Integer>> createBelRoutethroughs(SiteTemplate template, Element siteElement, WireHashMap wireMap, WireHashMap reverseWireMap) { Map<Integer, Set<Integer>> belRoutethroughMap = new HashMap<>(); for (Element belEl : siteElement.getChild("bels").getChildren("bel")) { String belName = belEl.getChildText("name"); Element routethroughs = belEl.getChild("routethroughs"); // bel has routethroughs if (routethroughs != null) { for (Element routethrough : routethroughs.getChildren("routethrough")) { String inputPin = routethrough.getChildText("input"); String outputPin = routethrough.getChildText("output"); String inputWireName = getIntrasiteWireName(template.getType(), belName, inputPin); String outputWireName = getIntrasiteWireName(template.getType(), belName, outputPin); Integer startEnum = we.getWireEnum(inputWireName); Integer endEnum = we.getWireEnum(outputWireName); // If the wire names for the routethrough do not exist, throw a parse exception telling the user if (startEnum == null) { throw new Exceptions.ParseException(String.format( "Cannot find intrasite wire \"%s\" for bel routethrough \"%s:%s:%s\". " + "Check the familyInfo.xml file for this routethrough and make sure the connections are correct.", inputWireName, template.getType(), inputPin, outputPin)); } else if (endEnum == null) { throw new Exceptions.ParseException(String.format( "Cannot find intrasite wire \"%s\" for bel routethrough \"%s:%s:%s\". " + "Check the familyInfo.xml file for this routethrough and make sure the connections are correct.", outputWireName, template.getType(), inputPin, outputPin)); } // add the routethrough to the routethrough map; Set<Integer> sinkWires = belRoutethroughMap.computeIfAbsent(startEnum, k -> new HashSet<>()); sinkWires.add(endEnum); } } } // create a new wire connection for each routethrough and adds them to the wire map for (Integer startWire : belRoutethroughMap.keySet()) { Set<Integer> sinkWires = belRoutethroughMap.get(startWire); WireConnection[] wireConnections = new WireConnection[sinkWires.size()]; int index = 0; for (Integer sink : sinkWires) { // routethroughs will be considered as pips in rapidSmith WireConnection wc = new WireConnection(sink, 0, 0, true); wireConnections[index] = wirePool.add(wc); index++; addSiteConnection(reverseWireMap, sink, startWire, true); } wireMap.put(startWire, wireConnections); } // return null if the belRoutethroughMap is empty return belRoutethroughMap.isEmpty() ? null : belRoutethroughMap; } private void addSiteConnection(WireHashMap whm, Integer source, Integer sink, boolean isPip) { WireConnection[] wcs = whm.get(source); if (wcs == null) { wcs = new WireConnection[1]; } else { wcs = Arrays.copyOf(wcs, wcs.length + 1); } whm.put(source, wcs); WireConnection wc = new WireConnection(sink, 0, 0, isPip); WireConnection pooled = wirePool.add(wc); wcs[wcs.length - 1] = pooled; } /** * Creates a PIP wire connection from each input of the mux to the output. * Additionally creates the attribute that would represent this connection * in XDL and adds it to the muxes structure. */ private void createAndAddMuxPips(PrimitiveDef def, PrimitiveElement el, WireHashMap forwardWireMap, WireHashMap reverserWireMap) { String elName = el.getName(); String sinkName = getIntrasiteWireName(def.getType(), elName, getOutputPin(el)); Integer sinkWire = we.getWireEnum(sinkName); WireConnection sinkWc = new WireConnection(sinkWire, 0, 0, true); WireConnection[] wcs = { wirePool.add(sinkWc) }; for (PrimitiveDefPin pin : el.getPins()) { if (!pin.isOutput()) { String srcName = getIntrasiteWireName(def.getType(), elName, pin.getInternalName()); Integer srcWire = we.getWireEnum(srcName); forwardWireMap.put(srcWire, wcs); addSiteConnection(reverserWireMap, sinkWire, srcWire, true); } } } /** * Gets the wire connections for this element and adds them to the wire maps */ private void addWireConnectionsForElement(PrimitiveDef def, PrimitiveElement el, WireHashMap forwardWireMap, WireHashMap reverseWireMap) { Map<Integer, List<WireConnection>> wcsMap = getWireConnectionsForElement(def, el); for (Map.Entry<Integer, List<WireConnection>> entry : wcsMap.entrySet()) { List<WireConnection> wcsList = entry.getValue(); WireConnection[] wcs = wcsList.toArray(new WireConnection[wcsList.size()]); forwardWireMap.put(entry.getKey(), wcs); for (WireConnection c : wcs) { addSiteConnection(reverseWireMap, c.getWire(), entry.getKey(), false); } } } /** * Returns all of the wire connections coming from the element * * @param def the primitive def for the current type * @param el the current element from the primitive def * @return all of the wire connection coming from the element */ private Map<Integer, List<WireConnection>> getWireConnectionsForElement(PrimitiveDef def, PrimitiveElement el) { Map<Integer, List<WireConnection>> wcsMap = new HashMap<>(); for (PrimitiveConnection conn : el.getConnections()) { // Only handle connections this element sources if (conn.isForwardConnection()) { Integer source = getPinSource(def, conn); Integer sink = getPinSink(def, conn); List<WireConnection> wcs = wcsMap.computeIfAbsent(source, k -> new ArrayList<>()); WireConnection wc = new WireConnection(sink, 0, 0, false); wcs.add(wirePool.add(wc)); } } return wcsMap; } private static String getOutputPin(PrimitiveElement el) { for (PrimitiveDefPin pin : el.getPins()) { if (pin.isOutput()) return pin.getInternalName(); } return null; } private Integer getPinSource(PrimitiveDef def, PrimitiveConnection conn) { String element = conn.getElement0(); String pin = conn.getPin0(); String wireName = getIntrasiteWireName(def.getType(), element, pin); return we.getWireEnum(wireName); } private Integer getPinSink(PrimitiveDef def, PrimitiveConnection conn) { String element = conn.getElement1(); String pin = conn.getPin1(); String wireName = getIntrasiteWireName(def.getType(), element, pin); return we.getWireEnum(wireName); } /** * Creates the site pin templates and adds them to the site template. */ private void createAndSetSitePins(PrimitiveDef def, SiteTemplate siteTemplate) { Map<String, SitePinTemplate> sources = new HashMap<>(); Map<String, SitePinTemplate> sinks = new HashMap<>(); for (PrimitiveDefPin pin : def.getPins()) { String name = pin.getInternalName(); SitePinTemplate template = new SitePinTemplate(name, def.getType()); template.setDirection(pin.getDirection()); String wireName = getIntrasiteWireName(def.getType(), name, name); template.setInternalWire(we.getWireEnum(wireName)); if (pin.getDirection() == PinDirection.IN) sinks.put(name, template); else sources.put(name, template); } siteTemplate.setSources(sources); siteTemplate.setSinks(sinks); } /** * Searches the device info file for the primitive type element of the * specified type. * * @param type the type of the element to retrieve * @return the JDOM element for the requested primitive type */ private Element getSiteTypeEl(SiteType type) { Element siteTypesEl = familyInfo.getRootElement().getChild("site_types"); for (Element siteTypeEl : siteTypesEl.getChildren("site_type")) { if (siteTypeEl.getChild("name").getText().equals(type.name())) return siteTypeEl; } throw new FileFormatException("no site type " + type.name() + " in familyInfo.xml"); } private Map<Tile, Map<Integer, Set<WireConnection>>> getWCsToAdd(boolean forward) { Map<Tile, Map<Integer, Set<WireConnection>>> wcsToAdd = new HashMap<>(); for (Tile tile : device.getTileMap().values()) { WireHashMap whm = (forward) ? tile.getWireHashMap() : tile.getReverseWireHashMap(); if (whm == null) continue; Map<Integer, Set<WireConnection>> tileWCsToAdd = new HashMap<>(); Set<Integer> tileSources = getSourceWiresOfTile(whm, forward); // Traverse all non-PIP wire connections starting at this source wire. If any // such wire connections lead to a sink wire that is not already a connection of // the source wire, mark it to be added as a connection for (int wireEnum : whm.keySet()) { // don't add any connections for unsourced wires if (!tileSources.contains(wireEnum)) continue; Set<WireConnection> wcToAdd = new HashSet<>(); Set<WireConnection> checkedConnections = new HashSet<>(); Queue<WireConnection> connectionsToFollow = new LinkedList<>(); // Add the wire to prevent building a connection back to itself checkedConnections.add(new WireConnection(wireEnum, 0, 0, false)); for (WireConnection wc : whm.get(wireEnum)) { if (!wc.isPIP()) { checkedConnections.add(wc); connectionsToFollow.add(wc); } } while (!connectionsToFollow.isEmpty()) { WireConnection midwc = connectionsToFollow.remove(); Tile midTile = midwc.getTile(tile); Integer midWire = midwc.getWire(); // Dead end checks WireHashMap midWhm = (forward) ? midTile.getWireHashMap() : midTile.getReverseWireHashMap(); if (midWhm == null || midWhm.get(midWire) == null) continue; for (WireConnection sinkwc : midWhm.get(midWire)) { if (sinkwc.isPIP()) continue; Integer sinkWire = sinkwc.getWire(); Tile sinkTile = sinkwc.getTile(midTile); int colOffset = midwc.getColumnOffset() + sinkwc.getColumnOffset(); int rowOffset = midwc.getRowOffset() + sinkwc.getRowOffset(); // This represents the wire connection from the original source to the sink wire WireConnection source2sink = new WireConnection(sinkWire, rowOffset, colOffset, false); boolean wirePreviouslyChecked = !checkedConnections.add(source2sink); // Check if we've already processed this guy and process him if we haven't if (wirePreviouslyChecked) continue; connectionsToFollow.add(source2sink); // Only add the connection if the wire is a sink. Other connections are // useless for wire traversing. WireHashMap swhm = (forward) ? sinkTile.getWireHashMap() : sinkTile.getReverseWireHashMap(); if (wireIsSink(swhm, sinkWire, forward)) wcToAdd.add(wirePool.add(source2sink)); } } // If there are wires to add, add them here by creating a new WireConnection array // combining the old and new wires. if (!wcToAdd.isEmpty()) { tileWCsToAdd.put(wireEnum, wcToAdd); } } if (!tileWCsToAdd.isEmpty()) wcsToAdd.put(tile, tileWCsToAdd); } return wcsToAdd; } private Map<Tile, Map<Integer, Set<WireConnection>>> getWCsToRemove(boolean forward) { Map<Tile, Map<Integer, Set<WireConnection>>> wcsToRemove = new HashMap<>(); // Traverse the entire device and find which wires to remove first for (Tile tile : device.getTileMap().values()) { WireHashMap whm = (forward) ? tile.getWireHashMap() : tile.getReverseWireHashMap(); if (whm == null) continue; Map<Integer, Set<WireConnection>> tileWCsToRemove = new HashMap<>(); // Create a set of wires that can be driven by other wires within the tile // We need this to do a fast look up later on Set<Integer> sourceWires = getSourceWiresOfTile(whm, forward); // Identify any wire connections that are not a "source" wire to "sink" wire // connection. Set<Integer> wires = new HashSet<>(whm.keySet()); for (Integer wireEnum : wires) { Set<WireConnection> wcToRemove = new HashSet<>(); for (WireConnection wc : whm.get(wireEnum)) { // never remove PIPs. We only are searching for different names // of the same wire. A PIP connect unique wires. if (wc.isPIP()) continue; Tile stile = wc.getTile(tile); WireHashMap swhm = (forward) ? stile.getWireHashMap() : stile.getReverseWireHashMap(); if (!sourceWires.contains(wireEnum) || !wireIsSink(swhm, wc.getWire(), forward)) { wcToRemove.add(wc); } } tileWCsToRemove.put(wireEnum, wcToRemove); } wcsToRemove.put(tile, tileWCsToRemove); } return wcsToRemove; } private Set<Integer> getSourceWiresOfTile(WireHashMap whm, boolean forward) { // when !forward, sourceWires is actually sinkWires Set<Integer> sourceWires = new HashSet<>(); for (Integer wireEnum : whm.keySet()) { if (forward && siteWireSourceSet.contains(wireEnum)) { sourceWires.add(wireEnum); } else if (!forward && siteWireSinkSet.contains(wireEnum)) { sourceWires.add(wireEnum); } for (WireConnection wc : whm.get(wireEnum)) { if (wc.isPIP()) { sourceWires.add(wc.getWire()); } } } return sourceWires; } // A wire is a sink if it is a site source (really should check in the tile sinks but // the wire type check is easier and should be sufficient or the wire is the source of // a PIP. // when !forward, this is really wireIsSource private boolean wireIsSink(WireHashMap whm, Integer wire, boolean forward) { if (forward && siteWireSinkSet.contains(wire)) { return true; } else if (!forward && siteWireSourceSet.contains(wire)) { return true; } if (whm == null || whm.get(wire) == null) return false; for (WireConnection wc : whm.get(wire)) { if (wc.isPIP()) return true; } return false; } /** * Add the missing wire connection and remove the unnecssary wires in a single * pass. It's easier to just recreate the wire hash maps with the corrections. */ private void makeWireCorrections(Map<Tile, Map<Integer, Set<WireConnection>>> wcsToAdd, Map<Tile, Map<Integer, Set<WireConnection>>> wcsToRemove, boolean forward) { HashPool<WireHashMap> tileWiresPool = new HashPool<>(); HashPool<WireArray> wireArrayPool = new HashPool<>(); for (Tile tile : device.getTileMap().values()) { WireHashMap orig = (forward) ? tile.getWireHashMap() : tile.getReverseWireHashMap(); if (orig == null) continue; // create a safe wire map to modify WireHashMap wireHashMap = new WireHashMap(); for (Integer wireEnum : orig.keySet()) { Set<WireConnection> wcs = new HashSet<>(Arrays.asList(orig.get(wireEnum))); if (wcsToRemove.containsKey(tile) && wcsToRemove.get(tile).containsKey(wireEnum)) wcs.removeAll(wcsToRemove.get(tile).get(wireEnum)); if (wcsToAdd.containsKey(tile) && wcsToAdd.get(tile).containsKey(wireEnum)) wcs.addAll(wcsToAdd.get(tile).get(wireEnum)); if (wcs.size() > 0) { WireConnection[] arrView = wcs.toArray(new WireConnection[wcs.size()]); wireHashMap.put(wireEnum, wireArrayPool.add(new WireArray(arrView)).array); } } // Update the tile with the new wire map. WireHashMap reduced = tileWiresPool.add(wireHashMap); if (forward) tile.setWireHashMap(reduced); else tile.setReverseWireConnections(reduced); } } /** * Remove duplicate wire resources in the tile. */ private WireHashMap removeDuplicateTileResources(WireHashMap orig) { for (Integer wireEnum : orig.keySet()) { WireArray unique = wireArrayPool.add(new WireArray(orig.get(wireEnum))); orig.put(wireEnum, unique.array); } return tileWiresPool.add(orig); } private static String getIntrasiteWireName(SiteType type, String element, String pinName) { return "intrasite:" + type.name() + "/" + element + "." + pinName; } /** * Parses the device info XML file for the specified device, and adds the information * to the {@link Device} object that is being created. If no device info file can be found * for the part, then a warning is printed to the console. * * TODO: parse the clock pads and add them to the device file * * @param device Device object created from the XDLRC parser */ public static boolean parseDeviceInfo(Device device) { Document deviceInfo = RSEnvironment.defaultEnv().loadDeviceInfo(device.getFamily(), device.getPartName()); if (deviceInfo != null) { createPackagePins(device, deviceInfo); return true; } return false; } /** * Creates a map from pad bel name -> corresponding package pin. This * information is needed when generating Tincr Checkpoints from * RS to be loaded into Vivado. */ private static void createPackagePins(Device device, Document deviceInfo) { Element pinMapRootEl = deviceInfo.getRootElement().getChild("package_pins"); if (pinMapRootEl == null) { throw new Exceptions.ParseException("No package pin information found in device info file: " + deviceInfo.getBaseURI() + ".\n" + "Either add the package pin mappings, or remove the device info file and regenerate."); } // Add the package pins to the device pinMapRootEl .getChildren("package_pin").stream().map(ppEl -> new PackagePin(ppEl.getChildText("name"), ppEl.getChildText("bel"), ppEl.getChild("is_clock") != null)) .forEach(packagePin -> device.addPackagePin(packagePin)); if (device.getPackagePins().isEmpty()) { throw new Exceptions.ParseException("No package pin information found in device info file: " + deviceInfo.getBaseURI() + ".\n" + "Either add the package pin mappings, or remove the device info file and regenerate."); } } private final class FamilyTypeListener extends XDLRCParserListener { @Override protected void enterXdlResourceReport(pl_XdlResourceReport tokens) { FamilyType family = FamilyType.valueOf(tokens.family.toUpperCase()); try { familyInfo = RSEnvironment.defaultEnv().loadFamilyInfo(family); } catch (IOException | JDOMException e) { throw new EnvironmentException("Failed to load family information file", e); } device.setFamily(family); } } private final class WireEnumeratorListener extends XDLRCParserListener { private static final int PIN_SET_CAPACITY = 10000; private final Set<String> wireSet = new TreeSet<>(); private final Set<String> inpinSet = new HashSet<>(PIN_SET_CAPACITY); private final Set<String> outpinSet = new HashSet<>(PIN_SET_CAPACITY); private SiteType currType; private String currElement; /** * Tracks special site pin wires. */ @Override protected void enterPinWire(pl_PinWire tokens) { String externalName = tokens.external_wire; if (tokens.direction.equals("input")) { inpinSet.add(externalName); } else { outpinSet.add(externalName); } } @Override protected void enterWire(pl_Wire tokens) { String wireName = tokens.name; wireSet.add(wireName); } @Override protected void enterPip(pl_Pip tokens) { pipSources.add(tokens.start_wire); String wireName = tokens.end_wire; pipSinks.add(wireName); } @Override protected void enterPrimitiveDef(pl_PrimitiveDef tokens) { currType = SiteType.valueOf(device.getFamily(), tokens.name); } @Override protected void enterElement(pl_Element tokens) { currElement = tokens.name; } @Override protected void enterElementPin(pl_ElementPin tokens) { String wireName = getIntrasiteWireName(currType, currElement, tokens.name); wireSet.add(wireName); } @Override protected void exitXdlResourceReport(pl_XdlResourceReport tokens) { Map<String, Integer> wireMap = new HashMap<>((int) (wireSet.size() / 0.75 + 1)); String[] wires = new String[wireSet.size()]; Set<Integer> sourceWireSetLocal = new HashSet<>(outpinSet.size()); Set<Integer> sinkWireSetLocal = new HashSet<>(inpinSet.size()); int i = 0; for (String wire : wireSet) { wires[i] = wire; wireMap.put(wire, i); if (inpinSet.contains(wire)) { sinkWireSetLocal.add(i); } if (outpinSet.contains(wire)) { sourceWireSetLocal.add(i); } i++; } we.setWireMap(wireMap); we.setWires(wires); // create the global source and sinks wire set siteWireSourceSet = sourceWireSetLocal; siteWireSinkSet = sinkWireSetLocal; } } private final class TileAndSiteGeneratorListener extends XDLRCParserListener { private ArrayList<Site> tileSites; private Tile currTile; @Override protected void enterXdlResourceReport(pl_XdlResourceReport tokens) { device.setPartName(PartNameTools.removeSpeedGrade(tokens.part)); } @Override protected void enterTiles(pl_Tiles tokens) { int rows = tokens.rows; int columns = tokens.columns; device.createTileArray(rows, columns); } @Override protected void enterTile(pl_Tile tokens) { int row = tokens.row; int col = tokens.column; currTile = device.getTile(row, col); currTile.setName(tokens.name); currTile.setType(TileType.valueOf(device.getFamily(), tokens.type)); tileSites = new ArrayList<>(); } @Override protected void enterPrimitiveSite(pl_PrimitiveSite tokens) { Site site = new Site(); site.setTile(currTile); site.setName(tokens.name); site.parseCoordinatesFromName(tokens.name); site.setIndex(tileSites.size()); site.setBondedType(BondedType.valueOf(tokens.bonded.toUpperCase())); List<SiteType> alternatives = new ArrayList<>(); SiteType type = SiteType.valueOf(device.getFamily(), tokens.type); alternatives.add(type); Element ptEl = getSiteTypeEl(type); Element alternativesEl = ptEl.getChild("alternatives"); if (alternativesEl != null) { FamilyType family = device.getFamily(); alternatives.addAll(alternativesEl.getChildren("alternative").stream() .map(alternativeEl -> SiteType.valueOf(family, alternativeEl.getChildText("name"))) .collect(Collectors.toList())); } SiteType[] arr = alternatives.toArray(new SiteType[alternatives.size()]); arr = alternativeTypesPool.add(new AlternativeTypes(arr)).types; site.setPossibleTypes(arr); tileSites.add(site); } @Override protected void exitTile(pl_Tile tokens) { // Create an array of sites (more compact than ArrayList) if (tileSites.size() > 0) { currTile.setSites(tileSites.toArray(new Site[tileSites.size()])); } else { currTile.setSites(null); } currTile = null; tileSites = null; } } private final class WireConnectionGeneratorListener extends XDLRCParserListener { private Tile currTile; private Integer currTileWire; private boolean currTileWireIsSource; private Integer pipStartWire; private Integer pipEndWire; private WireHashMap whm; @Override protected void enterTile(pl_Tile tokens) { int row = tokens.row; int col = tokens.column; currTile = device.getTile(row, col); whm = new WireHashMap(); } @Override protected void exitTile(pl_Tile tokens) { WireHashMap reduced = removeDuplicateTileResources(whm); currTile.setWireHashMap(reduced); currTile = null; } @Override protected void enterWire(pl_Wire tokens) { String wireName = tokens.name; currTileWire = we.getWireEnum(wireName); currTileWireIsSource = siteWireSourceSet.contains(currTileWire) || pipSinks.contains(wireName); } @Override protected void exitWire(pl_Wire tokens) { currTileWire = null; } @Override protected void enterConn(pl_Conn tokens) { String currWireName = tokens.wire; int currWire = we.getWireEnum(currWireName); boolean currWireIsSiteSink = siteWireSinkSet.contains(currWire); boolean currWireIsPIPSource = pipSources.contains(currWireName); boolean currWireIsSink = currWireIsSiteSink || currWireIsPIPSource; if (currTileWireIsSource || currWireIsSink) { Tile t = device.getTile(tokens.tile); WireConnection wc = new WireConnection(currWire, currTile.getRow() - t.getRow(), currTile.getColumn() - t.getColumn(), false); addConnection(currTileWire, wirePool.add(wc), whm); } } @Override protected void enterPip(pl_Pip tokens) { Integer startWire = we.getWireEnum(tokens.start_wire); Integer endWire = we.getWireEnum(tokens.end_wire); WireConnection wc = wirePool.add(new WireConnection(endWire, 0, 0, true)); addConnection(startWire, wc, whm); pipStartWire = startWire; pipEndWire = endWire; } @Override protected void exitPip(pl_Pip tokens) { pipStartWire = null; pipEndWire = null; } @Override protected void enterRoutethrough(pl_Routethrough tokens) { SiteType type = SiteType.valueOf(device.getFamily(), tokens.site_type); String[] parts = tokens.pins.split("-"); String inPin = parts[1]; String outPin = parts[2]; PIPRouteThrough currRouteThrough = new PIPRouteThrough(type, inPin, outPin); currRouteThrough = routeThroughPool.add(currRouteThrough); device.addRouteThrough(pipStartWire, pipEndWire, currRouteThrough); } void addConnection(int src, WireConnection dest, WireHashMap whm) { // Add the wire if it doesn't already exist if (whm.get(src) == null) { WireConnection[] tmp = { dest }; whm.put(src, tmp); } else { WireConnection[] currentConnections = whm.get(src); WireConnection[] tmp = new WireConnection[currentConnections.length + 1]; int i; for (i = 0; i < currentConnections.length; i++) { tmp[i] = currentConnections[i]; } tmp[i] = dest; Arrays.sort(tmp); whm.put(src, tmp); } } } private final class ReverseWireConnectionGeneratorListener extends XDLRCParserListener { private Tile currTile; private Integer currTileWire; private boolean currTileWireIsSink; private WireHashMap whm; @Override protected void enterTile(pl_Tile tokens) { int row = tokens.row; int col = tokens.column; currTile = device.getTile(row, col); whm = new WireHashMap(); } @Override protected void exitTile(pl_Tile tokens) { WireHashMap reduced = removeDuplicateTileResources(whm); currTile.setReverseWireConnections(reduced); currTile = null; } @Override protected void enterWire(pl_Wire tokens) { String wireName = tokens.name; currTileWire = we.getWireEnum(wireName); currTileWireIsSink = siteWireSinkSet.contains(currTileWire) || pipSources.contains(wireName); } @Override protected void exitWire(pl_Wire tokens) { currTileWire = null; } @Override protected void enterConn(pl_Conn tokens) { String currWireName = tokens.wire; int currWire = we.getWireEnum(currWireName); boolean currWireIsSiteSource = siteWireSourceSet.contains(currWire); boolean currWireIsPIPSink = pipSinks.contains(currWireName); boolean currWireIsSource = currWireIsSiteSource || currWireIsPIPSink; if (currTileWireIsSink || currWireIsSource) { Tile t = device.getTile(tokens.tile); WireConnection wc = new WireConnection(currWire, currTile.getRow() - t.getRow(), currTile.getColumn() - t.getColumn(), false); addConnection(currTileWire, wirePool.add(wc), whm); } } @Override protected void enterPip(pl_Pip tokens) { Integer startWire = we.getWireEnum(tokens.start_wire); Integer endWire = we.getWireEnum(tokens.end_wire); WireConnection wc = wirePool.add(new WireConnection(startWire, 0, 0, true)); addConnection(endWire, wc, whm); } void addConnection(int src, WireConnection dest, WireHashMap whm) { // Add the wire if it doesn't already exist if (whm.get(src) == null) { WireConnection[] tmp = { dest }; whm.put(src, tmp); } else { WireConnection[] currentConnections = whm.get(src); WireConnection[] tmp = new WireConnection[currentConnections.length + 1]; int i; for (i = 0; i < currentConnections.length; i++) { tmp[i] = currentConnections[i]; } tmp[i] = dest; Arrays.sort(tmp); whm.put(src, tmp); } } } private final class SourceAndSinkListener extends XDLRCParserListener { private Site currSite; private Set<Integer> tileSources; private Set<Integer> tileSinks; private Map<String, Integer> externalPinWires; @Override protected void enterTile(pl_Tile tokens) { tileSources = new TreeSet<>(); tileSinks = new TreeSet<>(); } @Override protected void exitTile(pl_Tile tokens) { tileSources = null; tileSinks = null; } @Override protected void enterPrimitiveSite(pl_PrimitiveSite tokens) { currSite = device.getSite(tokens.name); externalPinWires = new HashMap<>(); } @Override protected void enterPinWire(pl_PinWire tokens) { String name = tokens.name; PinDirection direction = tokens.direction.equals("input") ? PinDirection.IN : PinDirection.OUT; Integer externalWire = we.getWireEnum(tokens.external_wire); externalPinWires.put(name, externalWire); if (direction == PinDirection.IN) { tileSinks.add(externalWire); } else { tileSources.add(externalWire); } } @Override protected void exitPrimitiveSite(pl_PrimitiveSite tokens) { Map<SiteType, Map<String, Integer>> externalPinWiresMap = new HashMap<>(); externalPinWiresMap.put(currSite.getPossibleTypes()[0], externalWiresPool.add(externalPinWires)); SiteType[] alternativeTypes = currSite.getPossibleTypes(); for (int i = 1; i < alternativeTypes.length; i++) { Map<String, Integer> altExternalPinWires = new HashMap<>(); SiteType altType = alternativeTypes[i]; SiteTemplate site = device.getSiteTemplate(altType); for (String sitePin : site.getSources().keySet()) { Integer wire = getExternalWireForSitePin(altType, sitePin); altExternalPinWires.put(sitePin, wire); } for (String sitePin : site.getSinks().keySet()) { Integer wire = getExternalWireForSitePin(altType, sitePin); if (wire == null) System.out.println("There be an error here"); altExternalPinWires.put(sitePin, wire); } externalPinWiresMap.put(altType, externalWiresPool.add(altExternalPinWires)); } externalPinWiresMap = externalWiresMapPool.add(externalPinWiresMap); currSite.setExternalWires(externalPinWiresMap); externalPinWires = null; currSite = null; } private Integer getExternalWireForSitePin(SiteType altType, String sitePin) { Element pinEl = getPinmapElement(altType, sitePin); String connectedPin = sitePin; if (pinEl != null) { connectedPin = pinEl.getChildText("map"); } return externalPinWires.get(connectedPin); } private Element getPinmapElement(SiteType altType, String sitePin) { Element ptEl = getSiteTypeEl(currSite.getPossibleTypes()[0]); Element alternativesEl = ptEl.getChild("alternatives"); Element altEl = null; for (Element altTmpEl : alternativesEl.getChildren("alternative")) { if (altTmpEl.getChildText("name").equals(altType.name())) { altEl = altTmpEl; break; } } assert altEl != null; Element pinmapsEl = altEl.getChild("pinmaps"); Element pinEl = null; if (pinmapsEl != null) { for (Element pinTmpEl : pinmapsEl.getChildren("pin")) { if (pinTmpEl.getChildText("name").equals(sitePin)) { pinEl = pinTmpEl; break; } } } return pinEl; } } private class PrimitiveDefsListener extends XDLRCParserListener { private final PrimitiveDefList defs; private PrimitiveDef currDef; private PrimitiveElement currElement; private ArrayList<PrimitiveDefPin> pins; private ArrayList<PrimitiveElement> elements; PrimitiveDefsListener() { defs = new PrimitiveDefList(); device.setPrimitiveDefs(defs); } @Override protected void enterPrimitiveDef(pl_PrimitiveDef tokens) { currDef = new PrimitiveDef(); String name = tokens.name.toUpperCase(); currDef.setType(SiteType.valueOf(device.getFamily(), name)); pins = new ArrayList<>(tokens.pin_count); elements = new ArrayList<>(tokens.element_count); currDef.setPins(pins); currDef.setElements(elements); } @Override protected void exitPrimitiveDef(pl_PrimitiveDef tokens) { currDef.setPins(pins); currDef.setElements(elements); defs.add(currDef); } @Override protected void enterPin(pl_Pin tokens) { PrimitiveDefPin p = new PrimitiveDefPin(); p.setExternalName(tokens.external_name); p.setInternalName(tokens.internal_name); p.setDirection(tokens.direction.startsWith("output") ? PinDirection.OUT : PinDirection.IN); pins.add(p); } @Override protected void enterElement(pl_Element tokens) { currElement = new PrimitiveElement(); currElement.setName(tokens.name); currElement.setBel(tokens.isBel); } @Override protected void exitElement(pl_Element tokens) { // Determine the element type if (!currElement.isBel()) { if (currElement.getCfgOptions() != null && !currElement.getPins().isEmpty()) currElement.setMux(true); else if (currElement.getCfgOptions() != null) // && currElement.getPins() == null currElement.setConfiguration(true); else if (currElement.getName().startsWith("_ROUTETHROUGH")) currElement.setRouteThrough(true); else currElement.setPin(true); } elements.add(currElement); } @Override protected void enterElementPin(pl_ElementPin tokens) { PrimitiveDefPin elementPin = new PrimitiveDefPin(); elementPin.setExternalName(tokens.name); elementPin.setInternalName(tokens.name); elementPin.setDirection(tokens.direction.startsWith("output") ? PinDirection.OUT : PinDirection.IN); currElement.addPin(elementPin); } @Override protected void enterElementCfg(pl_ElementCfg tokens) { for (String cfg : tokens.cfgs) { currElement.addCfgOption(cfg); } } @Override protected void enterElementConn(pl_ElementConn tokens) { PrimitiveConnection c = new PrimitiveConnection(); c.setElement0(tokens.element0); c.setPin0(tokens.pin0); c.setForwardConnection(tokens.direction.equals("==>")); c.setElement1(tokens.element1); c.setPin1(tokens.pin1); currElement.addConnection(c); } } }