Package edu.byu.ece.rapidSmith.device

Source Code of edu.byu.ece.rapidSmith.device.DeviceFilesCreator

/*
* Copyright (c) 2010 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 2 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/gpl2.txt. You may also
* get a copy of the license at <http://www.gnu.org/licenses/>.
*
*/
package edu.byu.ece.rapidSmith.device;

import edu.byu.ece.rapidSmith.device.helper.Connection;
import edu.byu.ece.rapidSmith.device.helper.HashPool;
import edu.byu.ece.rapidSmith.device.helper.WireHashMap;
import edu.byu.ece.rapidSmith.util.*;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;

/**
* This class has a number of static methods to create Device and WireEnumerator objects from
* XDLRC files.  It also makes sure not to recreate XDLRC files if they already exist.
* @author Chris Lavin
* Created on: May 20, 2010
*/
public class DeviceFilesCreator{

  /**
   * Makes sure an XDLRC file exists, will create if necessary.
   * @param partName Name of the part to create the XDLRC file for.
   * @return Name of the existing or newly created XDLRC file.
   */
  public static String createXDLRC(String partName){
    FileTools.makeDirs(FileTools.getPartFolderPath(partName));
    String xdlrcFileName = FileTools.getPartFolderPath(partName) +
        partName + "_full.xdlrc";
   
    if(new File(xdlrcFileName).exists() && FileTools.getFileSize(xdlrcFileName) > 100000000){
      return xdlrcFileName;
    }
    if(!RunXilinxTools.generateFullXDLRCFile(partName, xdlrcFileName)){
      MessageGenerator.briefErrorAndExit("Exiting from XDLRC Generation failure.");
    }
    return xdlrcFileName;
  }
 
  /**
   * Either loads or creates the WireEnumerator for the family  of partName.
   * @param partName Name of the part to create WireEnumerator for.
   * @return The loaded or newly created WireEnumerator
   */
  public static WireEnumerator createWireEnumerator(String partName){
    FamilyType familyType = PartNameTools.getFamilyTypeFromPart(partName);
    String wireEnumeratorFileName = FileTools.getWireEnumeratorFileName(partName);
    if(new File(wireEnumeratorFileName).exists()){
      WireEnumerator we = new WireEnumerator();
      we.readCompactEnumFile(wireEnumeratorFileName, PartNameTools.getFamilyTypeFromPart(partName));
      return we;
    }
   
    ArrayList<String> partNames = new ArrayList<>();
    switch(familyType){
      case KINTEX7:
        partNames.add("xc7k160tfbg676");
        partNames.add("xc7k355tffg901");
        break;
      case SPARTAN2:
        partNames.add("xc2s100tq144");
        break;
      case SPARTAN2E:
        partNames.add("xc2s100eft256");
        partNames.add("xc2s600efg456");
        break;
      case SPARTAN3:
        partNames.add("xc3s1000fg320");
        break;
      case SPARTAN3A:
        partNames.add("xc3s50atq144");
        partNames.add("xc3s1400afg484");
        break;
      case SPARTAN3ADSP:
        partNames.add("xc3sd1800acs484");
        break;
      case SPARTAN3E:
        partNames.add("xc3s100evq100");
        partNames.add("xc3s250evq100");
        partNames.add("xc3s1200eft256");
        break;
      case SPARTAN6:
        partNames.add("xc6slx25tcsg324");
        partNames.add("xc6slx75tfgg676");
        break;
      case VIRTEX:
        partNames.add("xcv100bg256");
        partNames.add("xcv1000bg560");
        break;
      case VIRTEX2:
        partNames.add("xc2v1000bg575");
        break;
      case VIRTEX2P:
        partNames.add("xc2vp20fg676");
        partNames.add("xc2vpx20ff896");
        break;
      case VIRTEX4:
        partNames.add("xc4vfx12ff668");
        partNames.add("xc4vfx100ff1517");
        break;
      case VIRTEX5:
        partNames.add("xc5vlx20tff323");
        partNames.add("xc5vlx30ff324");
        partNames.add("xc5vfx30tff665");
        partNames.add("xc5vtx150tff1156");
        break;     
      case VIRTEX6:
        partNames.add("xc6vhx255tff1155");
        partNames.add("xc6vcx75tff484");     
        break;
      case VIRTEX7:
        partNames.add("xc7vx330tffg1157");
        partNames.add("xc7vx415tffg1157");
        partNames.add("xc7vx485tffg1157");
        partNames.add("xc7vh580thcg1155");
        partNames.add("xc7vh870thcg1931");
        break;
      case VIRTEXE:
        partNames.add("xcv2600efg1156");
        break;
      case ZYNQ:
        partNames.add("xc7z010clg400");
        partNames.add("xc7z020clg400");
        partNames.add("xc7z030fbg676");
        partNames.add("xc7z045fbg676");
        partNames.add("xc7z100ffg1156");
        break;
      case ARTIX7:
        partNames.add("xc7a100tcsg324");
        partNames.add("xc7a200tfbg484");
        break;
      default:
        MessageGenerator.briefErrorAndExit("Sorry, the device family "+ familyType +
        " is currently not supported.");
    }

   
    // Create XDLRC files for the wireEnumerator
    ArrayList<String> fileNames = new ArrayList<>();
    for(String name : partNames){
      fileNames.add(createXDLRC(name));
    }
   
    WireEnumerator we = new WireEnumerator();
    we.parseXDLRCFiles(fileNames,wireEnumeratorFileName);
   
    // Remove XDLRC files afterwards
    for(String fileName : fileNames){
      FileTools.deleteFile(fileName);
    }
    return we;
  }
 
  /**
   * Creates a tileMap for XDLRC parsing and creating device.  This creates a brief
   * version of the XDLRC to get tile names with coordinates.
   * @param partName The name of the part to create the tileMap for.
   * @return The created tile map
   */
  public static HashMap<String,Integer> createDeviceTileMap(String partName){
    partName = PartNameTools.removeSpeedGrade(partName);
    HashMap<String,Integer> tileMap = new HashMap<>();
    String xdlrcFileName = partName + "_brief.xdlrc";
    if(!RunXilinxTools.generateBriefXDLRCFile(partName, xdlrcFileName)){
      return null;
    }
    try{
      BufferedReader br = new BufferedReader(new FileReader(xdlrcFileName));
      String line;
      while((line = br.readLine()) != null) {
        String[] tokens = line.split("\\s+");
        if(tokens.length > 1 && tokens[1].equals("(tile")){
          int loc = Integer.parseInt(tokens[2]) << 16 | Integer.parseInt(tokens[3]);
          tileMap.put(tokens[4], loc);
        }
      }
      br.close();
    }
    catch(IOException e){
      MessageGenerator.briefErrorAndExit("Error Parsing XDLRC for TileMap Creation");
    }
   
    // Delete the brief xdlrcFile
    FileTools.deleteFile(xdlrcFileName);
   
    return tileMap;
  }
 
  /**
   * Creates the device and primitive defs specified by partName.
   * @param partName Name of the part to create
   * @param we Wire Enumerator corresponding to partName's family.
   */
  public static void createDevice(String partName, WireEnumerator we){
    String deviceFileName = FileTools.getDeviceFileName(partName);
    String primitiveDefsFileName = FileTools.getPrimitiveDefsFileName(partName);
    boolean createPrimitiveDefs = !new File(primitiveDefsFileName).exists();
    if(new File(deviceFileName).exists() && FileTools.getFileSize(deviceFileName) > 1000){
      if(FileTools.getDeviceVersion(partName).equals(Device.deviceFileVersion)){
        return;
      }
      else{
        MessageGenerator.briefMessage("Warning: existing device file for " + partName +
          " is not compatible with current version of tools.  Overwritting the existing" +
          " file with new version.");
      }
    }
   
    // Create XDLRC File if it already hasn't been created
    String xdlrcFileName = createXDLRC(partName);
    try{
      // Initialize Parser
      XDLRCParser parser = new XDLRCParser();
     
      // Parse XDLRC File
      parser.parseXDLRC(xdlrcFileName, createPrimitiveDefs);
     
      // Write out primitiveDefs
      if(createPrimitiveDefs){
        FileTools.saveToCompressedFile(parser.getPrimitiveDefs(), primitiveDefsFileName);
      }
     
      // Write the Device to File
      parser.getDevice().writeDeviceToCompactFile(deviceFileName);

      // reload the device
      Device dev = FileTools.loadDevice(partName);

      // Remove backwards edges
      addMissingWireConnections(dev, we);
      removeBackwardsEdgesFromDevice(dev, we);

      // Add all wires to wirePool for file creation
      for(Tile[] tileArray : dev.tiles){
        for(Tile t : tileArray){
          if(t.getWireHashMap() == null) continue;
          for(WireConnection[] wires : t.getWireHashMap().values()){
            if(wires == null) continue;
            for(int i = 0; i < wires.length; i++){
              wires[i] = dev.wirePool.add(wires[i]);
            }
          }
        }
      }

      // Rebuild pools for file creation
      for(Tile[] tileArray : dev.tiles){
        for(Tile t : tileArray){
          dev.incrementalRemoveDuplicateTileResources(t, we);
        }
      }
      for(WireConnection w : dev.routeThroughMap.keySet()){
        PIPRouteThrough p = dev.routeThroughPool.add(dev.getRouteThrough(w));
        dev.routeThroughMap.put(w, p);
      }
      dev.createWireConnectionEnumeration();
      dev.removeDuplicatePrimitivePinMaps();
      dev.populateSinkPins(we);
      dev.removeDuplicateTileSinks(we);
      dev.debugPoolCounts();

      // Overwrite old file
      dev.writeDeviceToCompactFile(FileTools.getDeviceFileName(partName));

      // Delete XDLRC file
      FileTools.deleteFile(xdlrcFileName);
     
    }
    catch(OutOfMemoryError e){
      System.out.println("The JVM ran out of memory, this parser needs a lot of memory.\n" +
          "Try -Xmx1600M as a parameter to java.");
      e.printStackTrace();
      System.exit(1);
    }
  }
 
  /**
   * Helper method to remove wires from an array and return a new array without the wire.
   * @param currentArray The current array.
   * @param toBeRemoved The wire to be removed.
   * @return A new array without the wire toBeRemoved.
   */
  private static WireConnection[] removeWire(WireConnection[] currentArray, WireConnection toBeRemoved){
    if(currentArray == null || currentArray.length == 0){
      return new WireConnection[0];
    }
    if(currentArray.length == 1 && currentArray[0].equals(toBeRemoved)){
      return new WireConnection[0];
    }
    int idx = -1;
    for(int i = 0; i < currentArray.length; i++){
      if(currentArray[i].equals(toBeRemoved)){
        idx = i;
        break;
      }
    }
    if(idx == -1){
      return currentArray;
    }
   
    WireConnection[] newArray = new WireConnection[currentArray.length-1];
    int i = 0;
    for(int j = 0; j < currentArray.length; j++){
      if(j != idx){
        newArray[i] = currentArray[j];
        i++;
      }
    }
    return newArray;
  }

  /**
   * This method will read in a device files and remove backward edges from the wire
   * connections in each tile.  This makes routing easier as it removes edges that don't
   * exist in the FPGA.
   */
  public static void removeBackwardsEdgesFromDevice(Device dev, WireEnumerator we){
    HashPool<WireHashMap> tileWiresPool = new HashPool<>();

    // Traverse the entire device and find which wires to remove first
    for(Tile tile : dev.getTileMap().values()) {
      if (tile.getWireHashMap() == null)
        continue;

      // create a safe wire map to modify
      WireHashMap wireHashMap = new WireHashMap(tile.getWireHashMap());

      // 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(we, tile);

      // Identify any wire connections that are not a "source" wire to "sink" wire
      // connection.
      Set<Integer> wires = new HashSet<>(tile.getWires());
      List<Connection> wiresToBeRemoved = new ArrayList<>();
      for (Integer wire : wires) {
        for (WireConnection wc : tile.getWireConnections(wire)) {
          // never remove PIPs.  We only are searching for different names
          // of the same wire.  A PIP connect unique wires.
          if (wc.isPIP())
            continue;
          if (!sourceWires.contains(wire) ||
              !wireIsSink(we, wc.getTile(tile), wc.getWire())) {
            wiresToBeRemoved.add(new Connection(wire, wc));
          }
        }
      }

      // Remove the edges by creating a new WireConnection arrays sans the
      // connection of interest.
      for (Connection c : wiresToBeRemoved) {
        WireConnection[] currentWires = wireHashMap.get(c.getWire());
        currentWires = removeWire(currentWires, c.getDestinationWire());
        wireHashMap.put(c.getWire(), currentWires);
      }
      // Update the tile with the new wire map.  Search for possible reuse.
      tile.setWireHashMap(tileWiresPool.add(wireHashMap));
    }
  }

  private static Set<Integer> getSourceWiresOfTile(WireEnumerator we, Tile tile) {
    Set<Integer> sourceWires = new HashSet<>();
    for(Integer wire : tile.getWires()){
      if (we.getWireType(wire) == WireType.SITE_SOURCE)
        sourceWires.add(wire);
      for(WireConnection wc : tile.getWireConnections(wire)){
        if(wc.isPIP()){
          sourceWires.add(wc.getWire());
        }
      }
    }
    return sourceWires;
  }

  private static void addMissingWireConnections(Device dev, WireEnumerator we) {
    HashPool<WireHashMap> tileWiresPool = new HashPool<>();

    for (Tile tile : dev.getTileMap().values()) {
      if (tile.getWireHashMap() == null)
        continue;

      // Create a safe copy to playaround with without messing up any other tiles wires
      WireHashMap whm = new WireHashMap(tile.getWireHashMap());

      // 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 (Integer wire : whm.keySet()) {
        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(wire, 0, 0, false));
        for (WireConnection wc : whm.get(wire)) {
          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
          if (midTile.getWireHashMap() == null || midTile.getWireConnections(midWire) == null)
            continue;

          for (WireConnection sinkwc : midTile.getWireConnections(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.
            if (wireIsSink(we, sinkTile, sinkWire))
              wcToAdd.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()) {
          List<WireConnection> newConnections = new ArrayList<>(Arrays.asList(whm.get(wire)));
          newConnections.addAll(wcToAdd);
          WireConnection[] arrView = newConnections.toArray(
              new WireConnection[newConnections.size()]);
          whm.put(wire, arrView);
        }
      }
    }
  }

  // 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.
  private static boolean wireIsSink(WireEnumerator we, Tile tile, Integer wire) {
    if (we.getWireType(wire) == WireType.SITE_SINK)
      return true;
    if (tile.getWireHashMap() == null || tile.getWireConnections(wire) == null)
      return false;
    for (WireConnection wc : tile.getWireConnections(wire)) {
      if (wc.isPIP())
        return true;
    }
    return false;
  }

  /**
   * Main method for this class that ensures all part files are created for the
   * partName given.
   * @param partName The name of the device to generate Device, PrimitiveDefs and Wire
   * Enumerator files for.
   */
  public static void createPartFiles(String partName){
    // Create Wire Enumerator if it already hasn't been created
    WireEnumerator we = DeviceFilesCreator.createWireEnumerator(partName);
   
    // Create Device and PrimitiveDefs if they already haven't been created
    DeviceFilesCreator.createDevice(partName, we);   
  }
 
  /**
   * Creates the appropriate primitive defs
   * @param args The first argument should be the Xilinx part name with package and speed grade
   */
  public static void main(String args[]){
    if(args.length != 1){
      MessageGenerator.briefMessageAndExit("USAGE: <Xilinx partname>");
    }
   
    createPartFiles(args[0]);
  }
}
TOP

Related Classes of edu.byu.ece.rapidSmith.device.DeviceFilesCreator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.