/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: PlacementAdapter.java * * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. * * Electric(tm) is free software; you can 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. * * Electric(tm) 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. * * You should have received a copy of the GNU General Public License * along with Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */ package com.sun.electric.tool.placement; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.sun.electric.database.ImmutableArcInst; import com.sun.electric.database.geometry.EPoint; import com.sun.electric.database.geometry.ERectangle; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.hierarchy.Export; import com.sun.electric.database.hierarchy.Library; import com.sun.electric.database.prototype.NodeProto; import com.sun.electric.database.prototype.PortCharacteristic; import com.sun.electric.database.prototype.PortProto; import com.sun.electric.database.topology.ArcInst; import com.sun.electric.database.topology.NodeInst; import com.sun.electric.database.topology.PortInst; import com.sun.electric.database.variable.TextDescriptor; import com.sun.electric.database.variable.Variable; import com.sun.electric.technology.technologies.Generic; import com.sun.electric.technology.technologies.Schematics; import com.sun.electric.tool.placement.PlacementFrame.PlacementNetwork; import com.sun.electric.tool.placement.forceDirected1.PlacementForceDirectedTeam5; import com.sun.electric.tool.placement.forceDirected2.PlacementForceDirectedStaged; import com.sun.electric.tool.placement.genetic1.g1.GeneticPlacement; import com.sun.electric.tool.placement.genetic2.PlacementGenetic; import com.sun.electric.tool.placement.metrics.AbstractMetric; import com.sun.electric.tool.placement.metrics.boundingbox.BBMetric; import com.sun.electric.tool.placement.metrics.mst.MSTMetric; import com.sun.electric.tool.placement.simulatedAnnealing1.SimulatedAnnealing; import com.sun.electric.tool.placement.simulatedAnnealing2.PlacementSimulatedAnnealing; import com.sun.electric.tool.placement.simulatedAnnealing3.PlacementSimulatedAnnealingRowCol; import com.sun.electric.tool.util.concurrent.utils.ElapseTimer; import com.sun.electric.util.math.Orientation; /** * PlacementExport describes exports in the cell. Placement algorithms do not * usually need this information: it exists as a way to communicate the * information internally. */ public class PlacementAdapter { private static final Logger logger = LoggerFactory.getLogger(PlacementAdapter.class); /** * Class to define a node that is being placed. This is a shadow class for * the internal Electric object "NodeInst". There are minor differences * between PlacementNode and NodeInst, for example, PlacementNode is * presumed to be centered in the middle, with port offsets based on that * center, whereas the NodeInst has a cell-center that may not be in the * middle. */ public static class PlacementNode extends PlacementFrame.PlacementNode { private final NodeProto original; private final String nodeName; private final int techBits; private final double width, height; private final List<PlacementFrame.PlacementPort> ports; private Map<String, Object> addedVariables; private final boolean terminal; /** * Method to create a PlacementNode object. * * @param type * the original Electric type of this PlacementNode. * @param name * the name to give the node once placed (can be null). * @param tBits * the technology-specific bits of this PlacementNode * (typically 0 except for specialized Schematics * components). * @param wid * the width of this PlacementNode. * @param hei * the height of this PlacementNode. * @param pps * a list of PlacementPort on the PlacementNode, indicating * connection locations. * @param terminal */ public PlacementNode(NodeProto type, String name, int tBits, double wid, double hei, List<PlacementPort> pps, boolean terminal) { original = type; nodeName = name; techBits = tBits; width = wid; height = hei; ports = new ArrayList<PlacementFrame.PlacementPort>(pps); this.terminal = terminal; } /** * Method to add variables to this PlacementNode. Variables are extra * name/value pairs, for example a transistor width and length. * * @param name * the name of the variable to add. * @param value * the value of the variable to add. */ public void addVariable(String name, Object value) { if (addedVariables == null) addedVariables = new HashMap<String, Object>(); addedVariables.put(name, value); } /** * Method to return the NodeProto of this PlacementNode. * * @return the NodeProto of this PlacementNode. */ public NodeProto getType() { return original; } /** * Method to return the name of NodeProto of this PlacementNode. * * @return the name NodeProto of this PlacementNode. */ public String getTypeName() { return original.getName(); } /** * Method to return a list of PlacementPorts on this PlacementNode. * * @return a list of PlacementPorts on this PlacementNode. */ public List<PlacementFrame.PlacementPort> getPorts() { return ports; } /** * Method to return the technology-specific information of this * PlacementNode. * * @return the technology-specific information of this PlacementNode * (typically 0 except for specialized Schematics components). */ public int getTechBits() { return techBits; } /** * Method to return the width of this PlacementNode. * * @return the width of this PlacementNode. */ @Override public double getWidth() { return width; } /** * Method to return the height of this PlacementNode. * * @return the height of this PlacementNode. */ @Override public double getHeight() { return height; } /** * @return the terminal */ public boolean isTerminal() { return terminal; } @Override public String toString() { String name = original.describe(false); if (nodeName != null) name += "[" + nodeName + "]"; if (getTechBits() != 0) name += "(" + getTechBits() + ")"; return name; } } /** * Class to define ports on PlacementNode objects. This is a shadow class * for the internal Electric object "PortInst". */ public static class PlacementPort extends PlacementFrame.PlacementPort { private PortProto proto; /** * Constructor to create a PlacementPort. * * @param x * the X offset of this PlacementPort from the center of its * PlacementNode. * @param y * the Y offset of this PlacementPort from the center of its * PlacementNode. * @param pp * the Electric PortProto of this PlacementPort. */ public PlacementPort(double x, double y, PortProto pp) { super(x, y); proto = pp; } /** * Method to return the Electric PortProto that this PlacementPort uses. * * @return the Electric PortProto that this PlacementPort uses. */ PortProto getPortProto() { return proto; } public String toString() { return proto.getName(); } } /** * Class to define an Export that will be placed in the circuit. */ public static class PlacementExport { private PlacementPort portToExport; private String exportName; private PortCharacteristic characteristic; /** * Constructor to create a PlacementExport with the information about an * Export to be created. * * @param port * the PlacementPort that is being exported. * @param name * the name to give the Export. * @param chr * the PortCharacteristic (input, output, etc.) to give the * Export. */ public PlacementExport(PlacementPort port, String name, PortCharacteristic chr) { portToExport = port; exportName = name; characteristic = chr; } PlacementPort getPort() { return portToExport; } String getName() { return exportName; } PortCharacteristic getCharacteristic() { return characteristic; } } /** * Static list of all Placement algorithms. When you create a new algorithm, * add it to the following list. */ static PlacementFrame[] placementAlgorithms = { new SimulatedAnnealing(), // team 2 new PlacementSimulatedAnnealing(), // team 6 new PlacementSimulatedAnnealingRowCol(), // team 6 modified for row/column placement new GeneticPlacement(), // team 3 new PlacementGenetic(), // team 4 new PlacementForceDirectedTeam5(), // team 5 new PlacementForceDirectedStaged(), // team 7 new PlacementMinCut(), new PlacementSimple(), new PlacementRandom() }; /** * Method to return a list of all Placement algorithms. * * @return a list of all Placement algorithms. */ public static PlacementFrame[] getPlacementAlgorithms() { return placementAlgorithms; } /** * Entry point for other tools that wish to describe a network to be placed. * Creates a cell with the placed network. * * @param lib * the Library in which to create the placed Cell. * @param cellName * the name of the Cell to create. * @param nodesToPlace * a List of PlacementNodes to place in the Cell. * @param allNetworks * a List of PlacementNetworks to connect in the Cell. * @param exportsToPlace * a List of PlacementExports to create in the Cell. * @param iconToPlace * non-null to place an instance of itself (the icon) in the * Cell. * @return the newly created Cell. */ public static Cell doPlacement(PlacementFrame pla, Library lib, String cellName, List<PlacementNode> nodesToPlace, List<PlacementNetwork> allNetworks, List<PlacementExport> exportsToPlace, NodeProto iconToPlace, Placement.PlacementPreferences prefs) { ElapseTimer timer = ElapseTimer.createInstance().start(); System.out.println("Running placement on cell '" + cellName + "' using the '" + pla.getAlgorithmName() + "' algorithm"); // do the real work of placement for (PlacementFrame.PlacementParameter par : pla.getParameters()) { par.setValue(prefs.getParameter(par)); } List<PlacementFrame.PlacementNode> nodesToPlaceCopy = new ArrayList<PlacementFrame.PlacementNode>( nodesToPlace); pla.runPlacement(nodesToPlaceCopy, allNetworks, cellName); if (logger.isDebugEnabled()) { InetAddress addr; try { addr = InetAddress.getLocalHost(); String hostname = addr.getHostName(); logger.debug("===================================================="); logger.debug("machine: " + hostname); logger.debug("algorithm: " + pla.getAlgorithmName()); logger.debug("#threads : " + pla.numOfThreads); logger.debug("#runtime : " + pla.runtime); logger.debug("cell : " + cellName); AbstractMetric bmetric = new BBMetric(nodesToPlaceCopy, allNetworks); logger.debug("### BBMetric: " + bmetric.toString()); AbstractMetric mstMetric = new MSTMetric(nodesToPlaceCopy, allNetworks); logger.debug("### MSTMetric: " + mstMetric.toString()); logger.debug("===================================================="); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // create a new cell for the placement results Cell newCell = Cell.makeInstance(lib, cellName); // newCellName // place the nodes in the new cell Map<PlacementNode, NodeInst> placedNodes = new HashMap<PlacementNode, NodeInst>(); for (PlacementNode plNode : nodesToPlace) { double xPos = plNode.getPlacementX(); double yPos = plNode.getPlacementY(); Orientation orient = plNode.getPlacementOrientation(); NodeProto np = plNode.getType(); if (np instanceof Cell) { Cell placementCell = (Cell) np; Rectangle2D bounds = placementCell.getBounds(); Point2D centerOffset = new Point2D.Double(bounds.getCenterX(), bounds.getCenterY()); orient.pureRotate().transform(centerOffset, centerOffset); xPos -= centerOffset.getX(); yPos -= centerOffset.getY(); } NodeInst ni = NodeInst.makeInstance(np, new Point2D.Double(xPos, yPos), np.getDefWidth(), np.getDefHeight(), newCell, orient, plNode.nodeName, plNode.getTechBits()); if (ni == null) System.out.println("Placement failed to create node"); else { if (plNode.isTerminal()) ni.setLocked(); placedNodes.put(plNode, ni); } if (plNode.addedVariables != null) { for (String varName : plNode.addedVariables.keySet()) { Object value = plNode.addedVariables.get(varName); Variable.Key key = Variable.newKey(varName); Variable var = ni.newDisplayVar(key, value); if (key == Schematics.SCHEM_RESISTANCE) { ni.setTextDescriptor( key, var.getTextDescriptor().withOff(0, 0.5) .withDispPart(TextDescriptor.DispPos.VALUE)); } else if (key == Schematics.ATTR_WIDTH) { ni.setTextDescriptor(key, var.getTextDescriptor().withOff(0.5, -1).withRelSize(1) .withDispPart(TextDescriptor.DispPos.VALUE)); } else if (key == Schematics.ATTR_LENGTH) { ni.setTextDescriptor(key, var.getTextDescriptor().withOff(-0.5, -1).withRelSize(0.5) .withDispPart(TextDescriptor.DispPos.VALUE)); } else { ni.setTextDescriptor(key, var.getTextDescriptor().withDispPart(TextDescriptor.DispPos.VALUE)); } } } } // place an icon if requested if (iconToPlace != null) { ERectangle bounds = newCell.getBounds(); EPoint center = new EPoint(bounds.getMaxX() + iconToPlace.getDefWidth(), bounds.getMaxY() + iconToPlace.getDefHeight()); NodeInst.makeInstance(iconToPlace, center, iconToPlace.getDefWidth(), iconToPlace.getDefHeight(), newCell); } // place exports in the new cell for (PlacementExport plExport : exportsToPlace) { PlacementPort plPort = plExport.getPort(); String exportName = plExport.getName(); PlacementNode plNode = (PlacementNode) plPort.getPlacementNode(); NodeInst newNI = placedNodes.get(plNode); if (newNI == null) continue; PortInst portToExport = newNI.findPortInstFromProto(plPort.getPortProto()); Export.newInstance(newCell, portToExport, exportName, plExport.getCharacteristic()); } ImmutableArcInst a = Generic.tech().unrouted_arc.getDefaultInst(newCell.getEditingPreferences()); long gridExtend = a.getGridExtendOverMin(); for (PlacementNetwork plNet : allNetworks) { PlacementFrame.PlacementPort lastPp = null; PortInst lastPi = null; for (PlacementFrame.PlacementPort plPort : plNet.getPortsOnNet()) { PlacementNode plNode = (PlacementNode) plPort.getPlacementNode(); NodeInst newNi = placedNodes.get(plNode); if (newNi != null) { PlacementPort thisPp = (PlacementPort) plPort; PortInst thisPi = newNi.findPortInstFromProto(thisPp.getPortProto()); if (lastPp != null) { // connect them EPoint lastPtComp = lastPi.getCenter(); EPoint thisPtComp = thisPi.getCenter(); ArcInst.newInstanceNoCheck(newCell, Generic.tech().unrouted_arc, null, null, lastPi, thisPi, lastPtComp, thisPtComp, gridExtend, ArcInst.DEFAULTANGLE, a.flags); } lastPp = thisPp; lastPi = thisPi; } } } timer.end(); System.out.println("\t(took " + timer + ")"); return newCell; } }