Package edu.byu.ece.rapidSmith.util

Source Code of edu.byu.ece.rapidSmith.util.HardMacroGenerator

/*
* 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.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import edu.byu.ece.rapidSmith.design.Attribute;
import edu.byu.ece.rapidSmith.design.Design;
import edu.byu.ece.rapidSmith.design.Instance;
import edu.byu.ece.rapidSmith.design.Module;
import edu.byu.ece.rapidSmith.design.Net;
import edu.byu.ece.rapidSmith.design.NetType;
import edu.byu.ece.rapidSmith.design.PIP;
import edu.byu.ece.rapidSmith.design.Pin;
import edu.byu.ece.rapidSmith.design.Port;
import edu.byu.ece.rapidSmith.device.PrimitiveSite;
import edu.byu.ece.rapidSmith.device.PrimitiveType;
import edu.byu.ece.rapidSmith.util.FileConverter;
import edu.byu.ece.rapidSmith.util.FileTools;
import edu.byu.ece.rapidSmith.util.MessageGenerator;


/**
* This class reads an XDL design file and converts it to a hard macro.  It will
* also create a VHDL wrapper to be able to instance the hard macro with the original
* interface of the design.
* @author Chris Lavin
* Created on: Jan 27, 2010
* Rewritten on: Jun 16 2010 by Jaren Lamprecht
*/

public class HardMacroGenerator {

  /** This variable keeps track of which instances should be removed from the original design */
  private ArrayList<Instance> instancesToRemove;
  /** This variable keeps track of which nets should be removed from the original design */
  private ArrayList<Net> netsToRemove;
  /** This variable keeps track of which instances should be added from the original design */
  private ArrayList<Instance> instancesToAdd;
  /** This variable keeps track of which nets should be added from the original design */
  private ArrayList<Net> netsToAdd;
  /** The XDL design that will be converted to a hard macro */
  private Design design;
  /** The hard macro that will be created, eventually will be added to design */
  private Module hardMacro;
  /** All of the InstanceTypes that are not allowed in hard macros  */
  private static HashSet<PrimitiveType> forbiddenTypes;
  static{
    // Populate the forbidden types for error checking later
    forbiddenTypes = new HashSet<PrimitiveType>();
    forbiddenTypes.add(PrimitiveType.TIEOFF);
    forbiddenTypes.add(PrimitiveType.IOB);
    forbiddenTypes.add(PrimitiveType.IOBM);
    forbiddenTypes.add(PrimitiveType.IOBS);
    forbiddenTypes.add(PrimitiveType.PMV);
    forbiddenTypes.add(PrimitiveType.DCM_ADV);
    forbiddenTypes.add(PrimitiveType.ISERDES);
    forbiddenTypes.add(PrimitiveType.OSERDES);
    forbiddenTypes.add(PrimitiveType.ILOGIC);
    forbiddenTypes.add(PrimitiveType.OLOGIC);
  }
  /** The output buffer for the VHDL wrapper to be created */
  private BufferedWriter vhd;
  /** The system's line terminator (\r\n:windows, \n:linux,...) */
  private String newLine;
  /** Stores the bus name found when isBusName() is called */
  private String _busName;
  /** Stores the bus bit number found when isBusName() is called */
  private int _busBitNumber;
  /** Optional file name for comparing VHDL top level names to original (for extra correctness)*/
  private String originalVHDLFileName;
  /**Graceful Failure reason*/
  private static String gracefulFailureReason;
  /**infrequent PIPs which constrain placement */
  private static HashSet<String> forbiddenPips;
  static {
    forbiddenPips = new HashSet<String>();
    forbiddenPips.add("OUT_S");
  }
  /** directions for finding slices */
  enum direction{up, down, left, right};
   
  /**
   * Constructor
   * @param design The XDL_Design that should be converted to a hard macro
   */
  public HardMacroGenerator(Design design){
    this.design = design;
    if(!(this.design.getExactFamilyName().contains("virtex4") || this.design.getExactFamilyName().contains("virtex5"))){
      MessageGenerator.briefErrorAndExit("HMG does not support " + design.getExactFamilyName());
    }

    // Get the System's line terminator string
    newLine = System.getProperty("line.separator");
   
    instancesToRemove = new ArrayList<Instance>();
    netsToRemove = new ArrayList<Net>();
    instancesToAdd = new ArrayList<Instance>();
    netsToAdd = new ArrayList<Net>();
    hardMacro = new Module();
 
  }
 
 
 
  /**
   * The main function which will convert XDL_Design design to a hard macro.
   * @param vhdName The output file name, used to generate the VHDL wrapper file name.
   * @return The newly created hard macro.
   */
  public Design convertToHardMacro(String vhdName){
    hardMacro.setName(design.getName() + "_HARD_MACRO");
    hardMacro.addAttribute(new Attribute("_SYSTEM_MACRO","","FALSE"));
    originalVHDLFileName = vhdName;
   
    // Initialize OutputBuffer for VHD file
    String fileNameVHD = design.getName()+ ".vhd";
   
    // Copy the original file to a _orig.vhd name so we can keep it / compare
    // before it gets overwritten
    if(originalVHDLFileName != null && originalVHDLFileName.equals(fileNameVHD)){
      FileTools.copyFile(originalVHDLFileName, design.getName() + "_orig" + ".vhd");
      originalVHDLFileName = design.getName() + "_orig" + ".vhd";
    }
   
    try {
      vhd = new BufferedWriter(new FileWriter(fileNameVHD));
    } catch (IOException e) {
      failAndExit("Problem creating file: " + fileNameVHD);
    }

    for(Instance inst : design.getInstances()){
      if(inst.getName().startsWith("IOBSLICE_")){
        inst.setType(PrimitiveType.IOB);
      }
    }
   
    //check for unplaced instances
    for(Instance instance: design.getInstances()){
      if(!instance.isPlaced()){
        failAndExit("This design is not fully placed.  Did PAR fail?");
      }
    }
   
    // Replace ILOGIC/OLOGIC with SLICE Registers
    handleIOLOGIC();
   
    // Make the design a hard macro
    design.setIsHardMacro(true);
    design.setName(Design.hardMacroDesignName);
   
    //Handle Nets
    handleNets();
   
    //Handle ISERDES/OSERDES
    handleIOSERDES();
   
    // Remove Instances and Nets before handling tieoffs
    design.getInstances().removeAll(instancesToRemove);
    design.getNets().removeAll(netsToRemove);       
    instancesToRemove.clear();
    netsToRemove.clear();
   
    // Remove TIEOFFs or Slices posing as tieoffs
    handleTIEOFFS();

    //add instances and nets
    for(Instance i: instancesToAdd){
      design.addInstance(i);
    }
    for(Net n: netsToAdd){
      design.addNet(n);
    }
   
    // Remove Instances and Nets
    design.getInstances().removeAll(instancesToRemove);
    design.getNets().removeAll(netsToRemove);
   
    netsToRemove.clear();
    instancesToRemove.clear();

    //remove SHAPEs
    handleSHAPE();
   
    // Move hard macro into design file
    for(Instance i: design.getInstances()){
      hardMacro.addInstance(i);
    }
    for(Net n: design.getNets()){
      hardMacro.addNet(n);
    }

    //clear the design
    design.getInstances().clear();
    design.getNets().clear();
    design.getAttributes().clear();
   
    //add the macro to the cleared design
    design.addModule(hardMacro);
    if(hardMacro.getInstances().size() == 0){
      failAndExit("This hard macro does not contain any instances.");
    }
    hardMacro.setAnchor(hardMacro.getInstances().iterator().next());
   
    //check for hard macro errors
    if(design.getName().compareTo("GRACEFUL_FAILURE") == 0){
      return design;
    }
   
    hmErrorCheck();
   
     // Create VHDL Wrapper before we return
    createVHDLWrapper();
    
    return design;
  }
 
  /**
   * This function removes the shape attributes from instances since adding several HMs
   * to a design results with the duplicate shape names.
   */
  public void handleSHAPE(){
    for(Instance i: design.getInstances()){
      ArrayList<Attribute> attributesToRemove = new ArrayList<Attribute>();
      for(Attribute a: i.getAttributes()){
        if(a.getValue().contains("XDL_SHAPE")){
          attributesToRemove.add(a);
        }
      }
      i.getAttributes().removeAll(attributesToRemove);
    }
  }
 
  /**
   * This function is questionable in its necessity as ILOGIC and OLOGIC primitives could
   * be part of a hard macro. We are assuming that they were not intentional.
   */
  public void handleIOLOGIC(){
    for(Instance inst : design.getInstances()){
      if(inst.getType().equals(PrimitiveType.ILOGIC)){
        boolean foundBadInstance = false;
        if(inst.getName().contains("XDL_DUMMY_IOI")){
          for(Attribute attr : inst.getAttributes()){
            if(attr.getPhysicalName().equals("_NO_USER_LOGIC")){
              foundBadInstance = true;
              instancesToRemove.add(inst);
              break;
            }
          }
        }
        if(!foundBadInstance){
          Instance newSLICE = createRegisterSlice(inst.getName());
          placeStaticSlice(newSLICE, false);
          newSLICE.setNetList(inst.getNetList());
          instancesToRemove.add(inst);
          instancesToAdd.add(newSLICE);
          for(Net net : inst.getNetList()){
            net.getPIPs().clear();
            for(Pin pin : net.getPins()){
              if(pin.getInstance().equals(inst)){
                pin.setInstance(newSLICE);
                String pinName = pin.getName();
                if(design.getExactFamilyName().contains("virtex4")){
                  if(pinName.equals("CE1")) pin.setPinName("CE");
                  if(pinName.equals("D")) pin.setPinName("BY");
                  if(pinName.equals("Q1")) pin.setPinName("YQ");
                }else if(design.getExactFamilyName().contains("virtex5")){
                  //TODO V5
                  if(pinName.equals("CE1")) pin.setPinName("CE");
                  if(pinName.equals("D")) pin.setPinName("DX");
                  if(pinName.equals("Q1")) pin.setPinName("DQ");
                }
              }
            }
          }
        }
      }
      else if(inst.getType().equals(PrimitiveType.OLOGIC)){
        boolean foundBadInstance = false;
        if(inst.getName().contains("XDL_DUMMY_IOI")){
          for(Attribute attr : inst.getAttributes()){
            if(attr.getPhysicalName().equals("_NO_USER_LOGIC")){
              foundBadInstance = true;
              instancesToRemove.add(inst);
              break;
            }
          }
        }
        if(!foundBadInstance){
          Instance newSLICE = createRegisterSlice(inst.getName());
          placeStaticSlice(newSLICE, false);
          newSLICE.setNetList(inst.getNetList());
          instancesToRemove.add(inst);
          instancesToAdd.add(newSLICE);
          for(Net net : inst.getNetList()){
            net.getPIPs().clear();
            for(Pin pin : net.getPins()){
              if(pin.getInstance().equals(inst)){
                pin.setInstance(newSLICE);
                String pinName = pin.getName();
                if(design.getExactFamilyName().contains("virtex4")){
                  if(pinName.equals("OCE")) pin.setPinName("CE");
                  if(pinName.equals("D1")) pin.setPinName("BY");
                  if(pinName.equals("OQ")) pin.setPinName("YQ");
                }else if(design.getExactFamilyName().contains("virtex5")){
                  //TODO V5
                  if(pinName.equals("OCE")) pin.setPinName("CE");
                  if(pinName.equals("D1")) pin.setPinName("DX");
                  if(pinName.equals("OQ")) pin.setPinName("DQ");
                }
              }
            } 
          }
        }
      }
    }

    design.getInstances().removeAll(instancesToRemove);
    instancesToRemove.clear();
   
    for(Instance i: instancesToAdd){
      design.addInstance(i);
    }
    //design.getInstances().addAll(instancesToAdd);
    instancesToAdd.clear();
  }
 
  /**
   * This is a helper method to convertToHardMacro which iterates through the nets
   * to turn the design into a hard macro
   */
  private void handleNets(){
    // Iterate through all nets to turn design into hard macro
    Pin pin = null;
    for(Net net: design.getNets()){
      ArrayList<Pin> pins = null;
     
      //check for forbidden pips and unroute
      boolean clearPips = false;
      for(PIP p : net.getPIPs()){
        if(forbiddenPips.contains(p.getStartWireName(design.getWireEnumerator()))
            ||forbiddenPips.contains(p.getEndWireName(design.getWireEnumerator()))){
          clearPips = true;
          break;
        }
      }
      if(clearPips){
        net.getPIPs().clear();
      }
     
      if(net.hasAttributes()){
        netsToRemove.add(net);
      }
      else if((pins = isNetConnectedToIOB(net)).size() > 0){
        handleIOBs(net, pins);
      }
      // Handle BUFG
      else if((pin = isNetOutputofBUFG(net)) != null){
       
        //check to see if the BUFG has an IOBSource before removing
        boolean IOBSource = false;
        for(Net n : pin.getInstance().getNetList()){
          if(n.getSource().getInstance().getType().equals(PrimitiveType.IOB)){
            IOBSource = true;
            break;
          }
        }
       
        if(IOBSource){
         
          // Remove BUFG and source pin
          instancesToRemove.add(pin.getInstance());
          net.getPins().remove(pin);
          net.getPIPs().clear();
         
          // Arbitrarily choose an inpin as the new port
          Pin port = net.getPins().get(0);
          String clkname = pin.getInstance().getName();
          String[] parts = clkname.split("_");
          clkname = "";
          for(String p : parts){
            if(p.contains("IBUF") || p.contains("BUFG")){
              break;
            }
            else{
              clkname += p + "_";
            }
          }
          if(clkname.endsWith("_")){
            clkname = clkname.substring(0, clkname.length()-1);
          }
         
          Port newPort = new Port(clkname +"_inport",port);
          hardMacro.getPorts().add(newPort);
          port.setPort(newPort);
         
        }

      }
      // Rip out DCMs/PMV
      else if((pin = isNetConnectedToDCMOrPMV(net)) != null){
        for(Pin p : net.getPins()){
          instancesToRemove.add(p.getInstance());
        }
        netsToRemove.add(net);
      }
     
    }
  }
 
  /**
   * This is a helper method to converToHardMacro which removes the
   * ISERDES and OSERDES
   */
  private void handleIOSERDES(){
    // Remove ISERDES/OSERDES
    for(Instance inst : design.getInstances()){
      if(inst.getType().equals(PrimitiveType.ISERDES) ||
         inst.getType().equals(PrimitiveType.OSERDES)){
        instancesToRemove.add(inst);
      }
      boolean foundBadInstance = false;
      if(inst.getName().contains("XDL_DUMMY_CLB")){
        for(Attribute attr : inst.getAttributes()){
          if(attr.getPhysicalName().equals("_NO_USER_LOGIC")){
            foundBadInstance = true;
            break;
          }
        }
        if(!foundBadInstance){
          inst.getAttributes().clear();
          if(design.getExactFamilyName().contains("virtex4")){
            inst.getAttributes().add(new Attribute("G","","#LUT:D=0"));
            inst.getAttributes().add(new Attribute("YUSED","","0"));
          }else if(design.getExactFamilyName().contains("virtex5")){
            //TODO V5
            inst.getAttributes().add(new Attribute("D6LUT","","#LUT:O6=0"));
            inst.getAttributes().add(new Attribute("DUSED","","0"));
          }
        }
      }
    }
  }
 
  /**
   * This is a helper method to convertToHardMacro which replaces the TIEOFFS or
   * their equivalent if mapped to a slice
   */
  private void handleTIEOFFS(){
    int diff = 10000;
    int uniqueGL = 100000;
    for(Net net : design.getNets()){
      if(net.isStaticNet()){
        if(net.getSource().getInstance().getType().equals(PrimitiveType.TIEOFF) || net.getSource().getInstance().getName().contains("XDL_DUMMY_CLB")){
          instancesToRemove.add(net.getSource().getInstance());
          netsToRemove.add(net);

          int num = 0;

          for(Pin p : net.getPins()){
            if(!p.isOutPin()){
              Port newPort = null;
              if(net.getName().startsWith("GLOBAL_LOGIC")){
                newPort = new Port(net.getName()+"_inport" + num,p);
                hardMacro.getPorts().add(newPort);
              }
              else{
                String type = "0";
                if(net.getType() == NetType.VCC){
                  type = "1";
                }
                newPort = new Port("GLOBAL_LOGIC"+type+"_"+(uniqueGL++)+"_inport" + num,p);
                hardMacro.getPorts().add(newPort);
              }
             
              // Create a new net for each pin created
              Net newNet = new Net();
              if(net.getName().charAt(12) == '0'){
                newNet.setName("GLOBAL_LOGIC0_" + diff++);
              }
              else{
                newNet.setName("GLOBAL_LOGIC1_" + diff++);
              }
              newNet.getPins().add(p);
              netsToAdd.add(newNet);
              p.setPort(newPort);
            }
            num++;
          }
        }
      }
      // Remove all gnd/vcc nets
      if(net.isStaticNet()){
        if(net.getType()== NetType.VCC)
          net.setName(net.getName() + "_VCC");
        else
          net.setName(net.getName() + "_GND");
        net.setType(NetType.WIRE);
      }
    }
  }

 
  /**
   * Checks the hard macro for errors such as unsupported instances, duplicates, etc.
   */
  private void hmErrorCheck(){
    //----------------------------------------------------------------------//
    // ERROR CHECKING
    //----------------------------------------------------------------------//
    HashSet<String> instanceNames = new HashSet<String>();
    HashSet<String> instanceLocations = new HashSet<String>();
    HashSet<String> netNames = new HashSet<String>();
    HashSet<String> portNames = new HashSet<String>();
     for(Instance inst: hardMacro.getInstances()){
      // Check for illegal instances in hard macro
      if(forbiddenTypes.contains(inst.getType())){
        if(inst.getType().equals(PrimitiveType.DCM_ADV) && inst.getName().startsWith("XIL_ML_UNUSED_DCM")){
          System.out.println("Error: " + inst.getType().toString() + ", " + inst.getName() +
          " found in hard macro.  This is a bug that needs to be fixed.");
        }
        else if(!inst.getType().equals(PrimitiveType.DCM_ADV)){
          System.out.println("Error: " + inst.getType().toString() + ", " + inst.getName() +
          " found in hard macro.  This is a bug that needs to be fixed.");
        }
      }
      if(inst.getName().contains("XDL_DUMMY_CLB")){
        for(Attribute attr : inst.getAttributes()){
          if(attr.getPhysicalName().equals("_NO_USER_LOGIC")){
            System.out.println("ERROR: Instance is statically configured, this will not work" +
                " as a hard macro: " + inst.getName());
            break;
          }
        }
      }
      // Check for unique instance names and locations
      if(!instanceNames.contains(inst.getName())){
        instanceNames.add(inst.getName());
      }
      else{
        System.out.println("ERROR: Duplicate instance name: " + inst.getName());
      }
     
      // Check for unique instance placements
      if(!instanceLocations.contains(inst.getPrimitiveSiteName())){
        instanceLocations.add(inst.getPrimitiveSiteName());
      }
      else{
        System.out.println("ERROR: Two instances placed at same location: " + inst.getName() + " " + inst.getPrimitiveSiteName());
      }
    }
     for(Port port : hardMacro.getPorts()){
       // Check for unique port names
      if(!portNames.contains(port.getName())){
        portNames.add(port.getName());
      }
      else{
        System.out.println("ERROR: Duplicate port name: " + port.getName());
      }
     }
     for(Net net : hardMacro.getNets()){
       // Check for illegal net types
       if(net.isStaticNet()){
         System.out.println("ERROR: Net type is illegal for hard macro: " + net.getName()
             +" of type: " + net.getType());
       }
       // Check for unique port names
      if(!netNames.contains(net.getName())){
        netNames.add(net.getName());
      }
      else{
        System.out.println("ERROR: Duplicate net name: " + net.getName());
      }
     }
  }
 
  /**
   * A helper method which checks if the net is driven by a BUFG.
   * @param net The net to test.
   * @return The pin that is the driving the net if driven by a BUFG, null otherwise.
   */
  private Pin isNetOutputofBUFG(Net net) {
    if(net.getSource() != null){
      return net.getSource().getInstance().getType().equals(PrimitiveType.BUFG) ? net.getSource() : null;
    }else{
      return null;
    }
  }
 
  /**
   * A helper method to check if a net connects to the un-needed DCM/PMV stuff.
   * @param net The net to check.
   * @return The pin connected to a DCM or PMV.
   */
  private Pin isNetConnectedToDCMOrPMV(Net net) {
    for(Pin pin : net.getPins()){
      if((pin.getInstance().getType().equals(PrimitiveType.DCM_ADV) && pin.getInstanceName().startsWith("XIL_ML_UNUSED_DCM"))||
          pin.getInstance().getType().equals(PrimitiveType.PMV)){
        return pin;
      }
    }
    return null;
  }
 
  /**
   * Creates a register slice
   * @param name
   * @return the newly created slice instance
   */
  private Instance createRegisterSlice(String name){
    Instance inst = new Instance();
    inst.setName(name);
    inst.setType(PrimitiveType.SLICEL);
    if(design.getExactFamilyName().contains("virtex4")){
      inst.getAttributes().add(new Attribute("DYMUX","","BY"));
      inst.getAttributes().add(new Attribute("FFY","","#FF"));
      inst.getAttributes().add(new Attribute("FFY_INIT_ATTR","","INIT0"));
      inst.getAttributes().add(new Attribute("FFY_SR_ATTR","","SRLOW"));
      inst.getAttributes().add(new Attribute("SYNC_ATTR","","SYNC"));
    }else if(design.getExactFamilyName().contains("virtex5")){
      //TODO V5
      //might need?: inst.getAttributes().add(new Attribute("CEUSED","","0"));
      inst.getAttributes().add(new Attribute("DFFMUX","","DX"));
      inst.getAttributes().add(new Attribute("DFF","","#FF"));
      inst.getAttributes().add(new Attribute("DFFINIT","","INIT0"));
      inst.getAttributes().add(new Attribute("DFFSR","","SRLOW"));
      inst.getAttributes().add(new Attribute("SYNC_ATTR","","SYNC"));
    }
    return inst;
  }
 
  /**
   * Returns a list of pins that are connected to IOBs in the current net.
   * @param net The net to test for IOB connections.
   * @return A list of pins connected to IOBs, the list will be empty if the net does not connect to IOBs.
   */
  private ArrayList<Pin> isNetConnectedToIOB(Net net){
    ArrayList<Pin> list = new ArrayList<Pin>();
    for(Pin pin : net.getPins()){
      if(isPinConnectedToIOB(pin)){
        list.add(pin);
      }
    }
    return list;
  }
 
  /**
   * A helper function to isNetConnectedToIOB which tests if a pin is connected to an IOB.
   * @param pin The pin to test.
   * @return True if the pin is connected to an IOB, false otherwise.
   */
  private boolean isPinConnectedToIOB(Pin pin){
    if(pin.getInstance().getType().equals(PrimitiveType.IOB)||
      pin.getInstance().getType().equals(PrimitiveType.IOBM)||
      pin.getInstance().getType().equals(PrimitiveType.IOBS)){
      return true;
    }
    return false;
  }
 
  /**
   * A helper method to convertToHardMacro() which handles the cases of the nets being
   * connected to IOBs.
   * @param net The current net to convert.
   * @param pins The pins that are connected to IOBs.
   */
  private void handleIOBs(Net net, ArrayList<Pin> pins) {
    // Add code to detect feedback on external nets
    // where the output is connected to IOBs, Xilinx has a bug in XDL conversion
   
    // If this is a net with more than one IOB, we currently only
    // have designs that are statically source'd that do this
    if(pins.size() > 1){ // CASE 5:
      if(!net.isStaticNet()){
        // Check for pass through nets, an IOB that drive IOBs
        boolean inputFound = false;
        boolean outputFound = false;
        for(Pin p : pins){
          if(!p.isOutPin()){
            inputFound = true;
          }
          else if(p.isOutPin()){
            outputFound = true;
          }
        }
        if(inputFound && outputFound){
          handlePassThruIOBs(net,pins);
          return;
        }
       
        String outputNames = "MULTI_OUTPUT_PORT";
       
       
        for(Pin pin : pins){
          // Remove the IOB instance
          if(isTriState(pin.getInstance())){
            failGracefully("This design contains tri-state IO, which is not yet supported by the HMG.");
          }
          instancesToRemove.add(pin.getInstance());
          outputNames += "-" + pin.getInstanceName();
          net.getPins().remove(pin);
       
        net.getPIPs().clear();
        Port newPort = new Port(outputNames+"_outport",net.getSource());
        hardMacro.getPorts().add(newPort);
        net.getSource().setPort(newPort);
      }
      else{
        // Remove the net, we'll create new nets for each IOB
        netsToRemove.add(net);
       
        // Remove the TIEOFF, Xilinx will choke if we don't
        if(net.getSource() == null){
          failAndExit("This net does not have a source: " + net);
        }
        if(!net.getSource().getInstance().getType().equals(PrimitiveType.TIEOFF)){
          failAndExit("1. This case is unexpected. Talk to Chris about getting it implemented.");
        }
       
        instancesToRemove.add(net.getSource().getInstance());
       
        for(Pin pin : pins){
          // Remove the IOB instance
          if(isTriState(pin.getInstance())){
            failGracefully("This design contains tri-state IO, which is not yet supported by the HMG.");
          }
          instancesToRemove.add(pin.getInstance());
         
          // Create New Net and static SLICE source with Pin connected to static SLICE
          Net newNet = new Net(pin.getInstance().getName() +"_"+ net.getType(), NetType.WIRE);
          Instance inst = createStaticSliceSource(net.getType());
          placeStaticSlice(inst, true);
          Pin newPin = null;
          if(design.getExactFamilyName().contains("virtex4")){
             newPin = new Pin(true,"Y",inst);
          }else if(design.getExactFamilyName().contains("virtex5")){
            //TODO V5
            newPin = new Pin(true,"D",inst);
          }
          newNet.replaceSource(newPin);
          netsToAdd.add(newNet);
          instancesToAdd.add(inst);
          Port newPort = new Port(pin.getInstance().getName()+"_outport",newPin);
          hardMacro.getPorts().add(newPort);
          newPin.setPort(newPort);
        }
      }
    }
    else{ // This is just a single IOB
      // There should only be 1 pin
      Pin pin = pins.get(0);
      // Remove IOB
      if(isTriState(pin.getInstance())){
        failGracefully("Sorry, this design contains tri-state IO.  Tri-state IO is not yet supported by the HMG.");
      }
      instancesToRemove.add(pin.getInstance());
      net.getPins().remove(pin);
      net.getPIPs().clear();
     
      if(pin.isOutPin()){
        // Check if this net drives the BUFG, if so, we don't want to create any ports
        // We'll do that with the output of the BUFG
        for(Pin p : net.getPins()){
          if(p.getInstance().getType().equals(PrimitiveType.BUFG)){
            netsToRemove.add(net);
            return;
          }
        }
        // CASE 1:
        // CASE 2:
        // Now create a port, we just choose an arbitrary one if there are more than one
        Pin p = net.getPins().get(0);
        //XDL_Pin p = pins.get(0); -- This is wrong here because we already removed this pin
        Port newPort = new Port(pin.getInstance().getName()+"_inport",p);
        hardMacro.addPort(newPort);
        p.setPort(newPort);
      }
      else{
        // Check if this is a static net
        if(net.isStaticNet()){
          if(!net.getSource().getInstance().getType().equals(PrimitiveType.TIEOFF)){
            failAndExit("2. This case is unexpected. Talk to Chris about getting it implemented.");
          }
         
          instancesToRemove.add(net.getSource().getInstance());
          netsToRemove.add(net);
         
          // Create New Net and static SLICE source with Pin connected to static SLICE
          Net newNet = new Net(pin.getInstance().getName() + "_" + net.getType(),NetType.WIRE);
          Instance inst = createStaticSliceSource(net.getType());
          placeStaticSlice(inst, true);
          Pin newPin = null;
          if(design.getExactFamilyName().contains("virtex4")){
             newPin = new Pin(true,"Y",inst);
          }else if(design.getExactFamilyName().contains("virtex5")){
            //TODO V5
            newPin = new Pin(true,"D",inst);
          }
          newNet.getPins().add(newPin);
          newNet.replaceSource(newPin);
          netsToAdd.add(newNet);
          instancesToAdd.add(inst);
          Port newPort = new Port(pin.getInstance().getName()+"_outport",newPin);
          hardMacro.getPorts().add(newPort);
          newPin.setPort(newPort);
        }
        else{
         
          // CASE 3:
          // CASE 4:
          Pin p = net.getSource();
          Port newPort = new Port(pin.getInstance().getName()+"_outport",p);
          hardMacro.getPorts().add(newPort);
          p.setPort(newPort);
        }
      }
    }
  }
 
  /**
   * Inserts a LUT to isolate input and output IOBs.  This is a restriction of hard macros.
   * @param net The current net to convert.
   * @param pins The pins that are connected to IOBs.
   */
  private void handlePassThruIOBs(Net net, ArrayList<Pin> pins) {
    System.out.println("WARNING: Design contains wires only connected to IOBs, net: " + net.getName());
    System.out.println("         This net has been divided by a LUT. Performance of signal will go down.");
    net.getPIPs().clear();
    Pin inPin = null;
   
    for(Pin pin : pins){
      // For each output IOB, create a new LUT and net
      if(!pin.isOutPin()){
        Net newOutputNet = new Net();
        Instance newLUT = createPassThruSlice();
        placeStaticSlice(newLUT, true);
        instancesToAdd.add(newLUT);
        newOutputNet.setName(net.getName() + "_OUTPUT");
        Pin newLUTPin = null;
        if(design.getExactFamilyName().contains("virtex4")){
           newLUTPin = new Pin(true,"Y",newLUT);
        }else if(design.getExactFamilyName().contains("virtex5")){
          //TODO V5
          newLUTPin = new Pin(true,"D",newLUT);
        }
        newOutputNet.getPins().add(newLUTPin);
        Pin newPin = null;
        if(design.getExactFamilyName().contains("virtex4")){
           newPin = new Pin(false,"G1",newLUT);
        }else if(design.getExactFamilyName().contains("virtex5")){
          //TODO V5
          newPin = new Pin(false,"D1",newLUT);
        }
        net.getPins().add(newPin);
        Port newPort = new Port(pin.getInstance().getName()+"_outport",
            newLUTPin);
        hardMacro.getPorts().add(newPort);
        newLUTPin.setPort(newPort);
      }
      else{
        inPin = pin;
      }
     
      // Remove the IOB instance
      instancesToRemove.add(pin.getInstance());
      net.getPins().remove(pin);
   
    if(net.getPins().size() < 1){
      failAndExit("ERROR: Check net: " + net.getName());
    }
    boolean containsBUFG = false;
    Pin bufgPin = null;
    for(Pin p : net.getPins()){
      if(p.getInstance().getType().equals(PrimitiveType.BUFG)){
        containsBUFG = true;
        bufgPin = p;
      }
    }
    if(!containsBUFG){
      Port newPort = new Port(inPin.getInstance().getName()+"_inport",
          net.getPins().get(0));
      hardMacro.getPorts().add(newPort);
      net.getPins().get(0).setPort(newPort);
       
    }
    else{
      net.getPins().remove(bufgPin);
    }
   
    return;   
  }
 
  /**
   * This function will look at already taken SLICE locations and try to place the slice
   * in a vacant location next to one of the already occupied slices.  This is only for
   * static slices.
   * @param slice The slice to be placed.
   */
  private void placeStaticSlice(Instance slice, boolean updateName){
    int xAvg = 0;
    int yAvg = 0;
    int avg = 0;
    HashSet<PrimitiveSite> sliceLocations = new HashSet<PrimitiveSite>();
    // Find all used SLICEs in the current design
    for(Instance inst : design.getInstances()){
      if(inst.getType().equals(PrimitiveType.SLICEL) ||
          inst.getType().equals(PrimitiveType.SLICEM)){
        sliceLocations.add(inst.getPrimitiveSite());
        if(!inst.getName().contains("slice")){
          xAvg += inst.getInstanceX();
          yAvg += inst.getInstanceY();
          avg++;
        }
      }
    }
    // Also includes SLICEs that will be added to the design
    for(Instance inst : instancesToAdd){
      if(inst.getType().equals(PrimitiveType.SLICEL) ||
          inst.getType().equals(PrimitiveType.SLICEM)){
        sliceLocations.add(inst.getPrimitiveSite());
        if(!inst.getName().contains("slice")){
          xAvg += inst.getInstanceX();
          yAvg += inst.getInstanceY();
          avg++;
        }
      }
    }
   
    //using the average in this way here is a quick and dirty way to exclude PORT_SLICE_HARD_MACROs
    //from being included in the averaging so that the new slices are centered correctly
   
    if(avg == 0){
      failAndExit("ERROR: This design contains static outputs (vcc/gnd) that could not " +
      "be supplied by a SLICE.  Does this design have any SLICEs in it?");
    }
   
    xAvg = xAvg / avg;
    yAvg = yAvg / avg;
   
    int x = xAvg;
    int y = yAvg;
    int maxX = xAvg+1;
    int maxY = yAvg+1;
    int minX = xAvg-1;
    int minY = yAvg;
    direction dir = direction.down;
   
    PrimitiveSite s = null;
   
    while(true){
      if((s = design.getDevice().getPrimitiveSites().get("SLICE_X" + Integer.toString(x) + "Y" + Integer.toString(y)))!=null){       
        if(!sliceLocations.contains(s)){
            slice.place(s);
            if(updateName){
              slice.setName("RS_DUMMY_"  + s);
            }
            return;
        }
      }
      if(dir == direction.down){
        if(y == minY){
          dir = direction.left;
          minY--;
          x--;
        }else{
          y--;
        }
      }else if(dir == direction.left){
        if(x == minX){
          dir = direction.up;
          minX--;
          y++;
        }else{
          x--;
        }     
      }else if(dir == direction.up){
        if(y == maxY){
          dir = direction.right;
          maxY++;
          x++;
        }else{
          y++;
       
      }else if(dir == direction.right){
        if(x == maxX){
          dir = direction.down;
          maxX++;
          y--;
        }else{
          x++;
        }
      }
    }

  }
 
  /**
   * This function will create an new SLICEL that will drive a static 0 or 1 indicated by
   * the type
   * @param netType Valid types are "gnd" and "vcc"
   * @return The newly create instance
   */
  private Instance createStaticSliceSource(NetType netType){
    Instance inst = new Instance();
    inst.setName("RS_DUMMY_CLB");
    inst.setType(PrimitiveType.SLICEL);
    if(design.getExactFamilyName().contains("virtex4")){
      inst.getAttributes().add(new Attribute("G","","#LUT:D=" + (netType.equals(NetType.GND) ? "0" :"1")));
      inst.getAttributes().add(new Attribute("YUSED","","0"));
    }else if(design.getExactFamilyName().contains("virtex5")){
      //TODO V5
      inst.getAttributes().add(new Attribute("DUSED","","0"));
      inst.getAttributes().add(new Attribute("D6LUT","","#LUT:O6=" + (netType.equals(NetType.GND) ? "0" :"1")));
    }
    return inst;
  }
 
  /**
   * Creates a slice for a signal to pass through
   * @return the slice
   */
  private Instance createPassThruSlice(){
    Instance inst = new Instance();
    inst.setName("XDL_LUT");
    inst.setType(PrimitiveType.SLICEL);
    if(design.getExactFamilyName().contains("virtex4")){
      inst.getAttributes().add(new Attribute("YUSED","","0"));
      inst.getAttributes().add(new Attribute("G","","#LUT:D=A1"));     
    }else if(design.getExactFamilyName().contains("virtex5")){
      //TODO V5
      inst.getAttributes().add(new Attribute("DUSED","","0"));
      inst.getAttributes().add(new Attribute("D6LUT","","#LUT:O6=A1"));
    }
    return inst;
  }
 
  /**
   * Returns true if the given IOB is a tri-state buffer
   * @param instance
   * @return True if tri-state
   */
  public boolean isTriState(Instance instance){
    for(Attribute cfg:instance.getAttributes()){
      if(cfg.getPhysicalName().compareTo("TUSED") == 0){
        if(cfg.getValue().compareTo("#OFF") != 0){
          return true;
        }else{
          break;
        }
      }
    }
    return false;
  }
 
  /**
   * This function will create the VHDL wrapper based on the hard macro created and the
   * different special cases that have changed the interface because of Xilinx hard macro restrictions.
   */
  private void createVHDLWrapper(){
    String designName = hardMacro.getName();
    HashMap<String,Integer> busNames = new HashMap<String,Integer>();
    HashMap<String,String> busDirections = new HashMap<String,String>();
    ArrayList<String> signalNames = new ArrayList<String>();
    ArrayList<String> multiOutputPortAssignments = new ArrayList<String>();
    int multiCount = 0;
   
    HashMap<String,String[]> signalMap = null;
   
    for(Port port : hardMacro.getPorts()){
      String portName = port.getName();
      String busName;
      Integer bitNumber = -1;
      if(portName.contains("MULTI_OUTPUT_PORT")){
        String[] parts = portName.split("-");
        for(String p : parts){
          if(p.contains("<")){
            busName = p.substring(0, p.indexOf("<"));
            bitNumber = Integer.parseInt(p.substring(p.indexOf("<")+1,p.indexOf(">")));
            if(busNames.get(busName) != null){
              if(busNames.get(busName) < bitNumber){
                busNames.put(busName,bitNumber);
                busDirections.put(busName,"out");
              }
            }
            else{
              busNames.put(busName,bitNumber);
              busDirections.put(busName,"out");
            }
          }else if(!p.contains("MULTI_OUTPUT_PORT")){
            signalNames.add(p.replace("_outport", "") + "\t: out std_logic");
          }
        }
      }
      else if(portName.contains("<")){
        busName = portName.substring(0, portName.indexOf("<"));
        bitNumber = Integer.parseInt(portName.substring(portName.indexOf("<")+1,portName.indexOf(">")));
        if(busNames.get(busName) != null){
          if(busNames.get(busName) < bitNumber){
            busNames.put(busName,bitNumber);
            busDirections.put(busName,portName.contains("_inport") ? "in" : "out");
          }
        }
        else{
          busNames.put(busName,bitNumber);
          busDirections.put(busName,portName.contains("_inport") ? "in" : "out");
        }
      }
      else if(!portName.contains("GLOBAL_LOGIC")){
        if(portName.endsWith("_inport")){
          //signalNames.add(portName.replace("_inport", ""));
          signalNames.add(portName.replace("_inport", "") + "\t: in std_logic");
        }
        else{
          //signalNames.add(portName.replace("_outport", ""));
          signalNames.add(portName.replace("_outport", "") + "\t: out std_logic");
        }
       
      }
    }
   
    for(Port port : hardMacro.getPorts()){
      String portName = port.getName();
     
      // Replace invalid VHDL identifier characters
      portName = portName.replaceAll("\\.","_");
      portName = portName.replaceAll("/","_");
      portName = portName.replaceAll("<","_");
      portName = portName.replaceAll(">","_");
      portName = portName.replaceAll("\\(", "_");
      portName = portName.replaceAll("\\)", "_");
     
      // Store up MultiOutput port names
      if(portName.startsWith("MULTI_OUTPUT_PORT")){
        String[] parts = portName.split("-");
        for(String part : parts){
          String assignment;
          if(isBusName(part, busNames)){
            assignment = _busName + "(" + _busBitNumber +
            ") <= multipleOutput_" + multiCount +";" + newLine;
            assignment = assignment.replaceAll("_{2,}","_");
            multiOutputPortAssignments.add(assignment);
          }
          else if (!part.startsWith("MULTI_OUTPUT_PORT")){
           
            if(part.endsWith("_outport")) part = part.replace("_outport", "");
            if(part.endsWith("_inport")) part = part.replace("_inport", "");
            assignment = part + " <= multipleOutput_" +
            multiCount +";" + newLine;
            assignment = assignment.replaceAll("_{2,}","_");
            multiOutputPortAssignments.add(assignment);
          }
         
        }
        multiCount++;
      }
      portName = portName.replaceAll("-","_");
      portName = portName.replaceAll("_{2,}","_");
      port.setName(portName);
    }
   
    // Check against original VHDL file (if given)
   
    if(originalVHDLFileName != null){
      signalMap = new HashMap<String,String[]>();
      try {
        BufferedReader reader = new BufferedReader(new FileReader(originalVHDLFileName));
        String line = null;
        boolean startParsing = false;
        boolean stopParsing = false;
       
        while((line = reader.readLine()) != null){
          if(startParsing && !stopParsing){
            Pattern pattern = Pattern.compile("\\s*([^:\\s]*)\\s*:\\s*([^\\s]*)\\s+([^;]*)[;\\s]*");         
            Matcher m = pattern.matcher(line);
            while(m.find()){
              if(m.group(2).toLowerCase().equals("in") || m.group(2).toLowerCase().equals("out") || m.group(2).toLowerCase().equals("inout")){
                String[] tmp = new String[3];
                tmp[0] = m.group(1); // signal_name               
                tmp[1] = m.group(2).toLowerCase(); // in/out/inout
                tmp[2] = m.group(3); // std_logic/std_logic_vector
                signalMap.put(tmp[0], tmp);
              }
            }
          }
          if(line.toLowerCase().contains("entity ")){
            startParsing = true;
            stopParsing = false;
          }
          if(line.toLowerCase().contains("end ")){
            stopParsing = true;
           
          }
        }
       
      } catch (FileNotFoundException e1) {
        failAndExit("Could not find VHDL file: " + originalVHDLFileName);
      } catch (IOException e) {
        failAndExit("Problem reading VHDL file: " + originalVHDLFileName);
      }
     
      // Do a little error checking.  Make sure the signal names extracted from XDL
      // match those from the supplied VHDL file
      String[] match = null;
      for(String s : signalNames){
        String[] parts = s.replace(':',' ').split("\\s+")
        match = signalMap.get(parts[0]);
        if(match != null){
          if(!match[1].equals(parts[1])){
            failAndExit("ERROR: Signal " + match[0] + " has wrong direction.");
          }
        }
        else{
          failAndExit("ERROR: Supplied VHDL file "+originalVHDLFileName+" does not have top level signal: " + parts[0]);
        }
      }
    }
   
    try {
      vhd.write(newLine);
      vhd.write("-------------------------------------------------------------------" + newLine);
      vhd.write("-- edu.byu.ece.rapidSmith.xdlUtilities.HardMacroGenerator" + newLine);
      vhd.write("-- time: " + FileTools.getTimeString() + newLine);
      vhd.write("-- " + newLine);
      vhd.write("-- This is the VHDL wrapper to correctly wrap the hard macro as " + newLine);
      vhd.write("-- it should be interfaced with its initial interface. " + newLine);
      vhd.write("--  - Chris Lavin 1/26/2010 " + newLine);
      vhd.write("-------------------------------------------------------------------" + newLine);
      vhd.write(newLine);
      vhd.write("-------------------------------------------------------------------" + newLine);
      vhd.write("-- LIBRARIES " + newLine);
      vhd.write("-------------------------------------------------------------------" + newLine);
      vhd.write("library ieee;" + newLine);
      vhd.write("use ieee.std_logic_1164.all;" + newLine);
      vhd.write("use ieee.std_logic_unsigned.all;" + newLine);
      vhd.write(newLine);
      vhd.write("-------------------------------------------------------------------" + newLine);
      vhd.write("-- ENTITY " + newLine);
      vhd.write("-------------------------------------------------------------------" + newLine);
      vhd.write("entity " + designName.replace("_HARD_MACRO", "") +" is" + newLine);
      vhd.write("  port (" + newLine);
      if(signalMap != null){ // Use names from user supplied VHDL file
        boolean firstTime = true;
        for(String[] signal : signalMap.values()){
          if(firstTime){
            firstTime = false;
          }
          else{
            vhd.write(";" + newLine);
          }
          String tmp = signal[2].toLowerCase();
          if(tmp.contains("(")){
            tmp = tmp.replace("unsigned", "std_logic_vector");
            tmp = tmp.replace("signed", "std_logic_vector");
          }
          else{
            tmp = tmp.replace("unsigned", "std_logic");
            tmp = tmp.replace("signed", "std_logic");
          }
          vhd.write("    " + signal[0] + " : " + signal[1] + " " + tmp);
        }
        vhd.write(newLine);
      }
      else{ // Use the names extracted from XDL and hope for the best
        for(String sig : signalNames){
          vhd.write("    " + sig);
          if(busNames.keySet().size() == 0){
            if(signalNames.get(signalNames.size()-1).equals(sig)){
              vhd.write(newLine);
            }
            else{
              vhd.write(";" + newLine);
           
          }
          else{
            vhd.write(";" + newLine);
          }
        }
        ArrayList<String> busNamesItr = new ArrayList<String>();
        busNamesItr.addAll(busNames.keySet());
        for(String sig : busNamesItr){
          int max = busNames.get(sig);
          vhd.write("    " + sig + "\t: "+ busDirections.get(sig)
              +" std_logic_vector("+max+" downto 0)");
          if(busNamesItr.get(busNamesItr.size()-1).equals(sig)){
            vhd.write(newLine);
          }
          else{
            vhd.write(";" + newLine);
          }         
        }
      }
      vhd.write("  );" + newLine);
      vhd.write("end "+ designName.replace("_HARD_MACRO", "") + ";" + newLine);
      vhd.write("-------------------------------------------------------------------" + newLine);
      vhd.write("-- ARCHITECTURE" + newLine);
      vhd.write("-------------------------------------------------------------------" + newLine);
      vhd.write("architecture behavioral of " + designName.replace("_HARD_MACRO", "") + " is" + newLine + newLine); // Add entity name
      vhd.write("component " + hardMacro.getName() + newLine);
      vhd.write("port(" + newLine);
      int portCounter = hardMacro.getPorts().size();
      for(Port port : hardMacro.getPorts()){
       
        vhd.write("  " + port.getName() + " :\t" +
            (port.getName().contains("_inport") ? "in" : "out") +
            " std_logic");
       
        portCounter--;
        if(portCounter == 0){
          vhd.write(newLine);
        }
        else{
          vhd.write(";" + newLine);
        }         
      }
      vhd.write(");" + newLine);
      vhd.write("end component;" + newLine + newLine);
     
      multiCount = 0;
      for(Port port : hardMacro.getPorts()){
        if(port.getName().startsWith("MULTI_OUTPUT_PORT")){
          vhd.write("signal multipleOutput_" + multiCount + " : std_logic;" + newLine);
          multiCount++;
        }
      }
     
      // Add all the signals we need
      vhd.write("signal ground : std_logic := '0';" + newLine);
      vhd.write("signal power : std_logic := '1';" + newLine + newLine);

      vhd.write("-------------------------------------------------------------------" + newLine);
      vhd.write("-- BEGIN" + newLine);
      vhd.write("-------------------------------------------------------------------" + newLine);
      vhd.write("begin" + newLine);
      if(multiOutputPortAssignments.size() > 0){
        vhd.write(newLine);
        vhd.write("-- Multiple Output Signal Assignments" + newLine);
        for(String s : multiOutputPortAssignments){
          vhd.write(s);
        }
       
        vhd.write(newLine);
      }
     
      vhd.write("instance0 : " + hardMacro.getName() + newLine);
      vhd.write("  port map(" + newLine);
      multiCount = 0;
      portCounter = hardMacro.getPorts().size();
      for(Port port : hardMacro.getPorts()){
       
        vhd.write("  " + port.getName() + " => ");
        if(port.getName().startsWith("GLOBAL_LOGIC0")){
          vhd.write("ground");
        }
        else if(port.getName().startsWith("GLOBAL_LOGIC1")){
          vhd.write("power");
        }
        else if(isBusName(port.getName(),busNames)){
          vhd.write(_busName + "(" + _busBitNumber + ")");
        }
        else if(port.getName().startsWith("MULTI_OUTPUT_PORT")){
          vhd.write("multipleOutput_"+multiCount);
          multiCount++;
        }
        else{
          vhd.write(port.getName().substring(0, port.getName().lastIndexOf("_")));
        }
       
        portCounter--;
        if(portCounter == 0){
          vhd.write(newLine);
        }
        else{
          vhd.write("," + newLine);
        }         
      } 
      vhd.write("  );" + newLine);
      vhd.write("end behavioral;" + newLine);
      vhd.write("-------------------------------------------------------------------" + newLine);
      vhd.write("-- END OF FILE" + newLine);
      vhd.write("-------------------------------------------------------------------" + newLine);
      vhd.write(newLine);
      vhd.close();
    } catch (IOException e) {
      failAndExit("Prolem writing vhd file.");
    }
   
  }
 
  /**
   * A helper function that can take in a string and determine if it is a member of a bus.
   * If it is a bus it will populate the variables _busName and _busBitNumber based in the name.
   * Otherwise it sets those variables to null and -1 respectively.
   * @param name Name of the string to check for a bus name
   * @param map The map of all the bus names already found.
   * @return True if name is a bus name, false otherwise.
   */
  private boolean isBusName(String name, HashMap<String,Integer> map){
    String part;
    int ndx = 0;
    int startIndex = 0;
    while(ndx < name.length()){
      startIndex = name.indexOf("_", ndx);
      if(startIndex < 0){
        _busName = null;
        _busBitNumber = -1;
        return false;
      }
      part = name.substring(0, startIndex);
      if(map.get(part) != null){
        _busName = part;
        try{
          _busBitNumber = Integer.parseInt(name.substring(part.length()+1, name.indexOf("_", part.length()+1)));
        }
        catch(NumberFormatException e){
          ndx = part.length() + 1;
          continue;
        }
        if(_busBitNumber > map.get(_busName)) {
          map.put(_busName, _busBitNumber);
        }
        return true;
      }
      else{
        ndx = part.length() + 1;
      }
    }
   
    _busName = null;
    _busBitNumber = -1;   
    return false;
  }
 
  /**
   * A simple error function to reduce code size.
   * @param s The error string
   */
  public static void failAndExit(String s){
    System.out.println(s);
    System.exit(1);
  }
 
  /**
   * For designs with detected unsupported structures
   * @param s
   */
  public void failGracefully(String s){
    gracefulFailureReason = s;
    design.setName("GRACEFUL_FAILURE");
  }
 
  public static void main(String[] args){
    if(args.length < 2 || args.length > 3){
      System.out.println("USAGE: <input.xdl|input.ncd> <output file type: xdl|nmc> [optional: original_vhdl_top.vhd]");
      System.exit(0);
    }   
    Design input = new Design();
    Design output;
    String originalVHDLFileName = args.length==3 ? args[2] : null;
    // If we are supplied an NCD, convert it to XDL
    if(args[0].endsWith(".ncd")){
      FileConverter.convertNCD2XDL(args[0]);
      if(!(new File(args[0]).exists())){
        HardMacroGenerator.failAndExit("XDL Generation failed, check your NCD file for correctness.");
      }
      input.loadXDLFile(args[0].replace(".ncd", ".xdl"));
    }
    else{
      input.loadXDLFile(args[0]);
    }
   
    HardMacroGenerator hmTool = new HardMacroGenerator(input);
    output = hmTool.convertToHardMacro(originalVHDLFileName);
   
    //detect graceful failure
    if(output.getName().compareTo("GRACEFUL_FAILURE") == 0){
      failAndExit(gracefulFailureReason);
    }
   
    // Output NMC if desired
    String xdlFileName = hmTool.hardMacro.getName() + ".xdl";
    if(args[1].toLowerCase().endsWith("nmc")){
      output.saveXDLFile(xdlFileName);
      FileConverter.convertXDL2NMC(xdlFileName);
      if(!(new File(xdlFileName).exists())){
        HardMacroGenerator.failAndExit("NMC Generation failed, re-run by hand to get error message.");
      }
    }
    else{
      output.saveXDLFile(xdlFileName);
    }
  }
}
TOP

Related Classes of edu.byu.ece.rapidSmith.util.HardMacroGenerator

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.