Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.sun.electric.tool.user.ViewChanges Maven / Gradle / Ivy
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: ViewChanges.java
*
* Copyright (c) 2004, 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.user;
import com.sun.electric.database.EditingPreferences;
import com.sun.electric.database.IdMapper;
import com.sun.electric.database.geometry.EPoint;
import com.sun.electric.database.geometry.Poly;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.EDatabase;
import com.sun.electric.database.hierarchy.Export;
import com.sun.electric.database.hierarchy.HierarchyEnumerator;
import com.sun.electric.database.hierarchy.Library;
import com.sun.electric.database.hierarchy.Nodable;
import com.sun.electric.database.hierarchy.View;
import com.sun.electric.database.network.Netlist;
import com.sun.electric.database.network.Network;
import com.sun.electric.database.prototype.NodeProto;
import com.sun.electric.database.prototype.PortCharacteristic;
import com.sun.electric.database.prototype.PortOriginal;
import com.sun.electric.database.prototype.PortProto;
import com.sun.electric.database.text.Name;
import com.sun.electric.database.topology.ArcInst;
import com.sun.electric.database.topology.Geometric;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.NodeInst.ExpansionState;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.database.variable.DisplayedText;
import com.sun.electric.database.variable.TextDescriptor;
import com.sun.electric.database.variable.VarContext;
import com.sun.electric.database.variable.Variable;
import com.sun.electric.technology.ArcProto;
import com.sun.electric.technology.Layer;
import com.sun.electric.technology.PrimitiveNode;
import com.sun.electric.technology.PrimitivePort;
import com.sun.electric.technology.SizeOffset;
import com.sun.electric.technology.Technology;
import com.sun.electric.technology.TransistorSize;
import com.sun.electric.technology.technologies.Generic;
import com.sun.electric.technology.technologies.Schematics;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.JobException;
import com.sun.electric.tool.generator.layout.GateLayoutGenerator;
import com.sun.electric.tool.generator.layout.StdCellParams;
import com.sun.electric.tool.user.dialogs.EDialog;
import com.sun.electric.tool.user.ui.EditWindow;
import com.sun.electric.tool.user.ui.TopLevel;
import com.sun.electric.tool.user.ui.WindowFrame;
import com.sun.electric.util.TextUtils;
import com.sun.electric.util.math.DBMath;
import com.sun.electric.util.math.EDimension;
import com.sun.electric.util.math.FixpTransform;
import com.sun.electric.util.math.GenMath;
import com.sun.electric.util.math.Orientation;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
/**
* Class for view-related changes to the circuit.
*/
public class ViewChanges
{
// constructor, never used
ViewChanges() {}
/****************************** CREATE AND VIEW A CELL ******************************/
/**
* Class to create a cell and display it in a new window.
*/
public static class CreateAndViewCell extends Job
{
private String cellName;
private Library lib;
private Cell c;
public CreateAndViewCell(String cellName, Library lib)
{
super("Create and View a Cell", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.cellName = cellName;
this.lib = lib;
startJob();
}
@Override
public boolean doIt() throws JobException
{
c = Cell.makeInstance(getEditingPreferences(), lib, cellName);
fieldVariableChanged("c");
return true;
}
@Override
public void terminateOK()
{
WindowFrame wf = WindowFrame.getCurrentWindowFrame();
if (User.isShowCellsInNewWindow()) wf = null;
if (wf == null) wf = WindowFrame.createEditWindow(c);
wf.setCellWindow(c, null);
}
}
/****************************** CONVERT OLD-STYLE MULTI-PAGE SCHEMATICS ******************************/
public static void convertMultiPageViews()
{
List multiPageCells = new ArrayList();
for(Iterator lIt = Library.getLibraries(); lIt.hasNext(); )
{
Library lib = lIt.next();
if (lib.isHidden()) continue;
for(Iterator cIt = lib.getCells(); cIt.hasNext(); )
{
Cell cell = cIt.next();
if (cell.getView().getFullName().startsWith("schematic-page-")) multiPageCells.add(cell);
}
}
if (multiPageCells.size() == 0)
{
System.out.println("No old-style multi-page schematics to convert");
return;
}
Collections.sort(multiPageCells/*, new TextUtils.CellsByName()*/);
new FixOldMultiPageSchematics(multiPageCells, User.getAlignmentToGrid());
}
/**
* Class to update old-style multi-page schematics in a new thread.
*/
private static class FixOldMultiPageSchematics extends Job
{
private List multiPageCells;
private EDimension alignment;
private boolean fromRight;
private ExpansionState expansionState;
private List nodesToExpand;
protected FixOldMultiPageSchematics(List multiPageCells, EDimension alignment)
{
super("Repair old-style Multi-Page Schematics", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.multiPageCells = multiPageCells;
this.alignment = alignment;
this.fromRight = User.isIncrementRightmostIndex();
this.expansionState = new ExpansionState(null, ExpansionState.JUSTTHISCELL);
this.nodesToExpand = new ArrayList();
startJob();
}
@Override
public boolean doIt() throws JobException
{
EditingPreferences ep = getEditingPreferences();
for(Cell cell : multiPageCells)
{
int pageNo = TextUtils.atoi(cell.getView().getFullName().substring(15));
String destCellName = cell.getName() + "{sch}";
Cell destCell = cell.getLibrary().findNodeProto(destCellName);
if (pageNo == 1 || destCell == null)
{
destCell = Cell.makeInstance(ep, cell.getLibrary(), destCellName);
if (destCell == null)
{
System.out.println("Unable to create cell " + cell.getLibrary().getName() + ":" + destCellName);
return false;
}
destCell.setMultiPage(true);
destCell.newVar(User.FRAME_SIZE, "d", ep);
}
// copy this page into the multipage cell
double dY = (pageNo - 1) * 1000;
List geomList = new ArrayList();
List textList = new ArrayList();
for(Iterator nIt = cell.getNodes(); nIt.hasNext(); )
geomList.add(nIt.next());
for(Iterator aIt = cell.getArcs(); aIt.hasNext(); )
geomList.add(aIt.next());
Clipboard.copyListToCell(destCell, geomList, textList, null, null, new Point2D.Double(0, dY),
true, fromRight, true, false, alignment, null, null, expansionState, nodesToExpand, ep);
// also copy any variables on the cell
for(Iterator vIt = cell.getVariables(); vIt.hasNext(); )
{
Variable var = vIt.next();
if (!var.isDisplay()) continue;
destCell.addVar(var.withOff(var.getXOff(), var.getYOff() + dY));
}
// delete the original
cell.kill();
}
return true;
}
}
/****************************** CHANGE A CELL'S VIEW ******************************/
public static void changeCellView(Cell cell, View newView)
{
// stop if already this way
if (cell.getView() == newView) return;
// database can't change icon/schematic views
if (cell.isIcon() || cell.isSchematic()) {
JOptionPane.showMessageDialog(TopLevel.getCurrentJFrame(),
"Cannot change view of icon/schematic",
"Change cell view failed", JOptionPane.ERROR_MESSAGE);
return;
}
if (newView == View.ICON || newView == View.SCHEMATIC) {
JOptionPane.showMessageDialog(TopLevel.getCurrentJFrame(),
"Cannot change " + cell.getView() + " to icon/schematic " + newView,
"Change cell view failed", JOptionPane.ERROR_MESSAGE);
return;
}
// warn if there is already a cell with that view
for(Iterator it = cell.getLibrary().getCells(); it.hasNext(); )
{
Cell other = it.next();
if (other.getView() != newView) continue;
if (!other.getName().equalsIgnoreCase(cell.getName())) continue;
// there is another cell with this name and view: warn that it will become old
int response = JOptionPane.showConfirmDialog(TopLevel.getCurrentJFrame(),
"There is already a cell with that view. Is it okay to make it an older version, and make this the newest version?");
if (response != JOptionPane.YES_OPTION) return;
break;
}
new ChangeCellView(cell, newView);
}
/**
* Class to change a cell's view in a new thread.
*/
private static class ChangeCellView extends Job
{
private Cell cell;
private View newView;
private IdMapper idMapper;
protected ChangeCellView(Cell cell, View newView)
{
super("Change View of " + cell + " to " + newView.getFullName(),
User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.cell = cell;
this.newView = newView;
startJob();
}
public boolean doIt() throws JobException
{
EDatabase database = cell.getDatabase();
idMapper = cell.setView(newView);
fieldVariableChanged("idMapper");
if (idMapper != null) {
cell = idMapper.get(cell.getId()).inDatabase(database);
}
return true;
}
public void terminateOK()
{
User.fixStaleCellReferences(idMapper);
EditWindow.repaintAll();
}
}
/****************************** MAKE A SKELETON FOR A CELL ******************************/
public static void makeSkeletonViewCommand()
{
Cell curCell = WindowFrame.needCurCell();
if (curCell == null) return;
// cannot skeletonize text-only views
if (curCell.getView().isTextView())
{
JOptionPane.showMessageDialog(TopLevel.getCurrentJFrame(),
"Cannot skeletonize textual views: only layout",
"Skeleton creation failed", JOptionPane.ERROR_MESSAGE);
return;
}
// warn if skeletonizing non-layout views
if (curCell.getView() != View.UNKNOWN && curCell.getView() != View.LAYOUT)
System.out.println("Warning: skeletonization only makes sense for layout cells, not " +
curCell.getView().getFullName());
new MakeSkeletonView(curCell);
}
private static class MakeSkeletonView extends Job
{
private Cell curCell;
private Cell skeletonCell;
private IconParameters iconParameters = IconParameters.makeInstance(true);
protected MakeSkeletonView(Cell curCell)
{
super("Make Skeleton View", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.curCell = curCell;
startJob();
}
@Override
public boolean doIt() throws JobException
{
EditingPreferences ep = getEditingPreferences();
// create the new icon cell
String skeletonCellName = curCell.getName() + "{lay.sk}";
skeletonCell = Cell.makeInstance(ep, curCell.getLibrary(), skeletonCellName);
if (skeletonCell == null)
{
throw new JobException("Cannot create Skeleton cell " + skeletonCellName);
}
boolean error = skeletonizeCell(curCell, skeletonCell, ep, iconParameters);
if (error) skeletonCell = null;
fieldVariableChanged("skeletonCell");
if (error) return false;
return true;
}
@Override
public void terminateOK()
{
if (skeletonCell != null)
{
System.out.println("Cell " + skeletonCell.describe(true) + " created with a skeletal representation of " +
curCell);
WindowFrame wf = WindowFrame.getCurrentWindowFrame();
if (User.isShowCellsInNewWindow()) wf = null;
if (wf == null) wf = WindowFrame.createEditWindow(skeletonCell);
wf.setCellWindow(skeletonCell, null);
}
}
}
/**
* Method to copy the skeletonized version of one Cell into another.
* @param curCell the original Cell to be skeletonized.
* @param skeletonCell the destination Cell that gets the skeletonized representation.
* @return true on error.
*/
public static boolean skeletonizeCell(Cell curCell, Cell skeletonCell, EditingPreferences ep, IconParameters iconParameters)
{
// place all exports in the new cell
Map newPortMap = new HashMap();
for(Iterator it = curCell.getPorts(); it.hasNext(); )
{
Export pp = (Export)it.next();
// traverse to the bottom of the hierarchy for this Export
PortOriginal fp = new PortOriginal(pp.getOriginalPort());
PortInst bottomPort = fp.getBottomPort();
NodeInst bottomNi = bottomPort.getNodeInst();
PortProto bottomPp = bottomPort.getPortProto();
FixpTransform subRot = fp.getTransformToTop();
Orientation newOrient = fp.getOrientToTop();
// create this node
Point2D center = new Point2D.Double(bottomNi.getAnchorCenterX(), bottomNi.getAnchorCenterY());
subRot.transform(center, center);
NodeInst newNi = NodeInst.makeInstance(bottomNi.getProto(), ep, center, bottomNi.getXSize(), bottomNi.getYSize(),
skeletonCell, newOrient, null);
if (newNi == null)
{
System.out.println("Cannot create node in this cell");
return true;
}
// export the port from the node
PortInst newPi = newNi.findPortInstFromProto(bottomPp);
Export npp = Export.newInstance(skeletonCell, newPi, pp.getName(), ep, pp.getCharacteristic());
if (npp == null)
{
System.out.println("Could not create port " + pp.getName());
return true;
}
npp.copyTextDescriptorFrom(pp, Export.EXPORT_NAME);
npp.copyVarsFrom(pp);
newPortMap.put(pp, npp);
}
// connect electrically-equivalent ports
Netlist netlist = curCell.getNetlist();
if (netlist == null)
{
System.out.println("Sorry, a deadlock aborted skeletonization (network information unavailable). Please try again");
return true;
}
// map exports in the original cell to networks
Map netMap = new HashMap();
for(Iterator it = curCell.getExports(); it.hasNext(); )
{
Export e = it.next();
Network net = netlist.getNetwork(e, 0);
netMap.put(e, net);
}
int numPorts = curCell.getNumPorts();
for(int i=0; i it = curCell.getNodes(); it.hasNext(); )
{
NodeInst ni = it.next();
NodeProto np = ni.getProto();
if (np != Generic.tech().essentialBoundsNode) continue;
NodeInst newNi = NodeInst.makeInstance(np, ep, ni.getAnchorCenter(),
ni.getXSize(), ni.getYSize(), skeletonCell, ni.getOrient(), null);
if (newNi == null)
{
System.out.println("Cannot create node in this cell");
return true;
}
newNi.setHardSelect();
if (np == Generic.tech().cellCenterNode) newNi.setVisInside();
}
// place an outline around the skeleton
Rectangle2D bounds = curCell.getBounds();
NodeInst boundNi = NodeInst.makeInstance(Generic.tech().invisiblePinNode, ep,
new Point2D.Double(bounds.getCenterX(), bounds.getCenterY()), bounds.getWidth(), bounds.getHeight(), skeletonCell);
if (boundNi == null)
{
System.out.println("Cannot create boundary node");
return true;
}
boundNi.setHardSelect();
return false;
}
/****************************** MAKE AN ICON FOR A CELL ******************************/
public static void makeIconViewCommand()
{
Cell curCell = WindowFrame.needCurCell();
if (curCell == null) return;
// see if the icon already exists and issue a warning if so
Cell iconCell = curCell.iconView();
if (iconCell != null)
{
int response = JOptionPane.showConfirmDialog(TopLevel.getCurrentJFrame(),
"Warning: Icon " + iconCell.describe(true) + " already exists. Create a new version?");
if (response != JOptionPane.YES_OPTION) return;
}
makeIconViewNoGUI(curCell, false, UserInterfaceMain.getEditingPreferences(), false);
}
public static void makeIconViewNoGUI(Cell curCell, boolean doItNow, EditingPreferences ep, boolean fixedValues)
{
IconParameters ip = IconParameters.makeInstance(true);
if (!fixedValues)
{
new MakeIconView(curCell, User.getAlignmentToGrid(), ep.getIconGenInstanceLocation(), ip, doItNow);
}
else
{
// in case of debugging mode, better to draw the body and leads
new MakeIconView(curCell, new EDimension(0.05, 0.05), 0, ip, doItNow);
}
}
private static class MakeIconView extends Job
{
private Cell curCell, iconCell;
private EDimension alignment;
private int exampleLocation;
private IconParameters ip;
private NodeInst iconNode;
private boolean doItNow;
// get icon style controls
private MakeIconView(Cell cell, EDimension alignment, int exampleLocation, IconParameters ip, boolean doItNow)
{
super("Make Icon View", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.curCell = cell;
this.alignment = alignment;
this.exampleLocation = exampleLocation;
this.ip = ip;
this.doItNow = doItNow;
if (doItNow)
{
try {doIt();} catch (Exception e) {e.printStackTrace();}
}
else
startJob();
}
@Override
public boolean doIt() throws JobException
{
EditingPreferences ep = getEditingPreferences();
iconCell = ip.makeIconForCell(curCell, ep);
if (iconCell == null) return false;
fieldVariableChanged("iconCell");
// Check user preference to see if an instance should be made in the original schematic
if (curCell.isSchematic() && exampleLocation != 4)
{
// place an icon in the schematic
Point2D iconPos = new Point2D.Double(0,0);
Rectangle2D cellBounds = curCell.getBounds();
Rectangle2D iconBounds = iconCell.getBounds();
double halfWidth = iconBounds.getWidth() / 2;
double halfHeight = iconBounds.getHeight() / 2;
switch (exampleLocation)
{
case 0: // upper-right
iconPos.setLocation(cellBounds.getMaxX()+halfWidth, cellBounds.getMaxY()+halfHeight);
break;
case 1: // upper-left
iconPos.setLocation(cellBounds.getMinX()-halfWidth, cellBounds.getMaxY()+halfHeight);
break;
case 2: // lower-right
iconPos.setLocation(cellBounds.getMaxX()+halfWidth, cellBounds.getMinY()-halfHeight);
break;
case 3: // lower-left
iconPos.setLocation(cellBounds.getMinX()-halfWidth, cellBounds.getMinY()-halfHeight);
break;
}
DBMath.gridAlign(iconPos, alignment);
double px = iconCell.getBounds().getWidth();
double py = iconCell.getBounds().getHeight();
iconNode = NodeInst.makeInstance(iconCell, ep, iconPos, px, py, curCell);
if (!doItNow)
fieldVariableChanged("iconNode");
}
return true;
}
@Override
public void terminateOK()
{
EditWindow wnd = EditWindow.getCurrent();
if (wnd != null)
{
if (wnd.getCell() == curCell && !doItNow)
{
if (iconNode != null)
{
Highlighter highlighter = wnd.getHighlighter();
highlighter.clear();
highlighter.addElectricObject(iconNode, curCell);
highlighter.finished();
} else if (iconCell != null)
{
WindowFrame wf = WindowFrame.getCurrentWindowFrame();
if (User.isShowCellsInNewWindow()) wf = null;
if (wf == null) wf = WindowFrame.createEditWindow(iconCell);
wf.setCellWindow(iconCell, null);
}
}
}
}
}
/**
* Method to determine the side of the icon that port "pp" belongs on.
*/
public static int iconTextRotation(Export pp, EditingPreferences ep)
{
PortCharacteristic character = pp.getCharacteristic();
// special detection for power and ground ports
if (pp.isPower()) character = PortCharacteristic.PWR;
if (pp.isGround()) character = PortCharacteristic.GND;
// see which side this type of port sits on
if (character == PortCharacteristic.IN) return ep.getIconGenInputRot();
if (character == PortCharacteristic.OUT) return ep.getIconGenOutputRot();
if (character == PortCharacteristic.BIDIR) return ep.getIconGenBidirRot();
if (character == PortCharacteristic.PWR) return ep.getIconGenPowerRot();
if (character == PortCharacteristic.GND) return ep.getIconGenGroundRot();
if (character.isClock()) return ep.getIconGenClockRot();
return ep.getIconGenInputRot();
}
/****************************** CONVERT TO SCHEMATICS ******************************/
/**
* Method to converts the current Cell into a schematic.
*/
public static void makeSchematicView()
{
Cell oldCell = WindowFrame.needCurCell();
if (oldCell == null) return;
new MakeSchematicView(oldCell);
}
private static class MakeSchematicView extends Job
{
private Cell oldCell;
private Cell newCell;
private IconParameters iconParameters = IconParameters.makeInstance(true);
protected MakeSchematicView(Cell cell)
{
super("Make Schematic View", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.oldCell = cell;
startJob();
}
@Override
public boolean doIt() throws JobException
{
newCell = convertSchematicCell(oldCell, getEditingPreferences(), iconParameters);
if (newCell == null) return false;
fieldVariableChanged("newCell");
return true;
}
public void terminateOK()
{
if (newCell != null)
{
System.out.println("Cell " + newCell.describe(true) + " created with a schematic representation of " + oldCell);
WindowFrame wf = WindowFrame.getCurrentWindowFrame();
if (User.isShowCellsInNewWindow()) wf = null;
if (wf == null) wf = WindowFrame.createEditWindow(newCell);
wf.setCellWindow(newCell, null);
}
}
}
private static Cell convertSchematicCell(Cell oldCell, EditingPreferences ep, IconParameters iconParameters)
{
// create cell in new technology
Cell newCell = makeNewCell(oldCell.getName(), View.SCHEMATIC, oldCell, null, ep);
if (newCell == null) return null;
// create the parts in this cell
Map newNodes = new HashMap();
buildSchematicNodes(oldCell, newCell, newNodes, ep, iconParameters);
buildSchematicArcs(oldCell, newCell, newNodes, ep);
// now make adjustments for manhattan-ness
// makeArcsManhattan(newCell);
// set "fixed-angle" if reasonable
for(Iterator it = newCell.getArcs(); it.hasNext(); )
{
ArcInst ai = it.next();
Point2D headPt = ai.getHeadLocation();
Point2D tailPt = ai.getTailLocation();
if (headPt.getX() == tailPt.getX() && headPt.getY() == tailPt.getY()) continue;
if ((GenMath.figureAngle(tailPt, headPt)%450) == 0) ai.setFixedAngle(true);
}
return newCell;
}
/**
* Method to create a new cell called "newcellname" that is to be the
* equivalent to an old cell in "cell". The view type of the new cell is
* in "newcellview" and the view type of the old cell is in "cellview"
*/
private static Cell makeNewCell(String newCellName, View newCellView, Cell cell, Library lib, EditingPreferences ep)
{
// create the new cell
String cellName = newCellName;
if (newCellView.getAbbreviation().length() > 0)
{
cellName = newCellName + newCellView.getAbbreviationExtension();
}
if (lib == null) lib = cell.getLibrary();
Cell newCell = Cell.makeInstance(ep, lib, cellName);
if (newCell == null)
System.out.println("Could not create cell: " + cellName); else
System.out.println("Creating new cell: " + cellName + " from cell " + cell.describe(false));
return newCell;
}
private static void buildSchematicNodes(Cell cell, Cell newCell, Map newNodes,
EditingPreferences ep, IconParameters iconParameters)
{
// for each node, create a new node in the newcell, of the correct logical type.
for(Iterator it = cell.getNodes(); it.hasNext(); )
{
NodeInst mosNI = it.next();
PrimitiveNode.Function type = getNodeType(mosNI);
NodeInst schemNI = null;
if (type == PrimitiveNode.Function.UNKNOWN) continue;
if (type == null)
{
// a cell
Cell proto = (Cell)mosNI.getProto();
Cell equivCell = proto.otherView(View.SCHEMATIC);
if (equivCell == null)
equivCell = convertSchematicCell(proto, ep, iconParameters);
schemNI = makeSchematicNode(equivCell, ep, mosNI, equivCell.getDefWidth(), equivCell.getDefHeight(), mosNI.getAngle(), 0, newCell);
} else if (type.isPin())
{
// compute new x, y coordinates
NodeProto prim = Schematics.tech().wirePinNode;
schemNI = makeSchematicNode(prim, ep, mosNI, prim.getDefWidth(ep), prim.getDefHeight(ep), 0, 0, newCell);
} else
{
int rotate = mosNI.getAngle();
rotate = (rotate + 2700) % 3600;
PrimitiveNode prim = Schematics.tech().transistorNode;
int bits = prim.getPrimitiveFunctionBits(mosNI.getFunction());
schemNI = makeSchematicNode(prim, ep, mosNI, prim.getDefWidth(ep), prim.getDefHeight(ep), rotate, bits, newCell);
// add in the size
TransistorSize ts = mosNI.getTransistorSize(VarContext.globalContext);
if (ts != null)
{
if (mosNI.getFunction().isFET())
{
// set length/width
TextDescriptor td = ep.getNodeTextDescriptor().withRelSize(0.5).withOff(-0.5, -1);
schemNI.newVar(Schematics.ATTR_LENGTH, new Double(ts.getDoubleLength()), td);
td = ep.getNodeTextDescriptor().withRelSize(1).withOff(0.5, -1);
schemNI.newVar(Schematics.ATTR_WIDTH, new Double(ts.getDoubleWidth()), td);
} else
{
// set area
schemNI.newVar(Schematics.ATTR_AREA, new Double(ts.getDoubleLength()), ep);
}
}
}
// store the new node in the old node
newNodes.put(mosNI, schemNI);
// reexport ports
if (schemNI != null)
{
for(Iterator eIt = mosNI.getExports(); eIt.hasNext(); )
{
Export mosPP = eIt.next();
PortInst schemPI = convertPort(mosNI, mosPP.getOriginalPort().getPortProto(), schemNI);
if (schemPI == null) continue;
Export schemPP = Export.newInstance(newCell, schemPI, mosPP.getName(), ep, mosPP.getCharacteristic());
if (schemPP != null)
{
schemPP.copyTextDescriptorFrom(mosPP, Export.EXPORT_NAME);
schemPP.copyVarsFrom(mosPP);
}
}
}
}
}
private static NodeInst makeSchematicNode(NodeProto prim, EditingPreferences ep, NodeInst orig, double wid, double hei, int angle, int techSpecific, Cell newCell)
{
Point2D newLoc = new Point2D.Double(orig.getAnchorCenterX(), orig.getAnchorCenterY());
Orientation orient = Orientation.fromAngle(angle);
NodeInst newNI = NodeInst.makeInstance(prim, ep, newLoc, wid, hei, newCell, orient, null, techSpecific);
return newNI;
}
/**
* for each arc in cell, find the ends in the new technology, and
* make a new arc to connect them in the new cell.
*/
private static void buildSchematicArcs(Cell cell, Cell newcell, Map newNodes, EditingPreferences ep)
{
for(Iterator it = cell.getArcs(); it.hasNext(); )
{
ArcInst mosAI = it.next();
NodeInst mosHeadNI = mosAI.getHeadPortInst().getNodeInst();
NodeInst mosTailNI = mosAI.getTailPortInst().getNodeInst();
NodeInst schemHeadNI = newNodes.get(mosHeadNI);
NodeInst schemTailNI = newNodes.get(mosTailNI);
if (schemHeadNI == null || schemTailNI == null) continue;
PortInst schemHeadPI = convertPort(mosHeadNI, mosAI.getHeadPortInst().getPortProto(), schemHeadNI);
PortInst schemTailPI = convertPort(mosTailNI, mosAI.getTailPortInst().getPortProto(), schemTailNI);
if (schemHeadPI == null || schemTailPI == null) continue;
// create the new arc
ArcInst schemAI = ArcInst.makeInstanceBase(Schematics.tech().wire_arc, ep, 0, schemHeadPI, schemTailPI, null, null, mosAI.getName());
if (schemAI == null) continue;
schemAI.setFixedAngle(false);
schemAI.setRigid(false);
}
}
/**
* Method to find the logical portproto corresponding to the mos portproto of ni
*/
private static PortInst convertPort(NodeInst mosNI, PortProto mosPP, NodeInst schemNI)
{
PrimitiveNode.Function fun = getNodeType(schemNI);
if (fun == null)
{
// a cell
PortProto schemPP = schemNI.getProto().findPortProto(mosPP.getName());
if (schemPP == null) return null;
return schemNI.findPortInstFromProto(schemPP);
}
if (fun.isPin())
return schemNI.getOnlyPortInst();
// a transistor
int portNum = 1;
for(Iterator it = mosNI.getProto().getPorts(); it.hasNext(); )
{
PortProto pp = it.next();
if (pp == mosPP) break;
portNum++;
}
if (portNum == 4) portNum = 3; else
if (portNum == 3) portNum = 1;
for(Iterator it = schemNI.getProto().getPorts(); it.hasNext(); )
{
PortProto schemPP = it.next();
portNum--;
if (portNum > 0) continue;
return schemNI.findPortInstFromProto(schemPP);
}
return null;
}
// private static final int MAXADJUST = 5;
//
// private static void makeArcsManhattan(Cell newCell)
// {
// // copy the list of nodes in the cell
// List nodesInCell = new ArrayList();
// for(Iterator it = newCell.getNodes(); it.hasNext(); )
// nodesInCell.add(it.next());
//
// // examine all nodes and adjust them
// double [] x = new double[MAXADJUST];
// double [] y = new double[MAXADJUST];
// for(NodeInst ni : nodesInCell)
// {
// if (ni.isCellInstance()) continue;
// PrimitiveNode.Function fun = ni.getFunction();
// if (fun != PrimitiveNode.Function.PIN) continue;
//
// // see if this pin can be adjusted so that all wires are manhattan
// int count = 0;
// for(Iterator aIt = ni.getConnections(); aIt.hasNext(); )
// {
// Connection con = aIt.next();
// ArcInst ai = con.getArc();
// int otherEnd = 1 - con.getEndIndex();
// if (con.getPortInst().getNodeInst() == ai.getPortInst(otherEnd).getNodeInst()) continue;
// x[count] = ai.getLocation(otherEnd).getX();
// y[count] = ai.getLocation(otherEnd).getY();
// count++;
// if (count >= MAXADJUST) break;
// }
// if (count == 0) continue;
//
// // now adjust for all these points
// double xp = ni.getAnchorCenterX();
// double yp = ni.getAnchorCenterY();
// double bestDist = Double.MAX_VALUE;
// double bestX = 0, bestY = 0;
// for(int i=0; i bestDist) continue;
// bestDist = dist;
// bestX = x[i]; bestY = y[j];
// }
//
// // if there was a better place, move the node
// if (bestDist != Double.MAX_VALUE)
// ni.move(bestX-xp, bestY-yp);
// }
// }
/**
* Method to figure out if a NodeInst is a MOS component
* (a wire or transistor). If it's a transistor, return its function;
* if it's a passive connector, return PrimitiveNode.Function.PIN;
* if it's a cell, return null; else return PrimitiveNode.Function.UNKNOWN.
*/
private static PrimitiveNode.Function getNodeType(NodeInst ni)
{
if (ni.isCellInstance()) return null;
PrimitiveNode.Function fun = ni.getFunction();
if (fun.isTransistor()) return fun;
if (fun.isPin() || fun.isContact() ||
fun == PrimitiveNode.Function.NODE || fun == PrimitiveNode.Function.CONNECT ||
fun == PrimitiveNode.Function.SUBSTRATE || fun == PrimitiveNode.Function.WELL)
return PrimitiveNode.Function.PIN;
return PrimitiveNode.Function.UNKNOWN;
}
/****************************** CONVERT TO ALTERNATE LAYOUT ******************************/
/**
* Method to converts the current Cell into a layout in a given technology.
*/
public static void makeLayoutView()
{
EditWindow wnd = EditWindow.needCurrent();
if (wnd == null) return;
Cell oldCell = wnd.getCell();
if (oldCell == null) return;
new MakeNewViewDialog(oldCell, wnd);
}
/**
* Class to handle the "Make New View" dialog.
*/
public static class MakeNewViewDialog extends EDialog
{
private Cell oldCell;
private VarContext context;
private Technology oldTech;
private JComboBox newTechnology, standardCellLibrary;
private JCheckBox putInSeparateLibrary;
private JTextField separateLibraryName;
private JLabel jLabel2;
/** Creates new form */
private MakeNewViewDialog(Cell oldCell, EditWindow wnd)
{
super(TopLevel.getCurrentJFrame(), true);
this.oldCell = oldCell;
initComponents();
context = wnd.getVarContext();
if (context == null) context = VarContext.globalContext;
sepLibChanged();
finishInitialization();
pack();
setVisible(true);
}
protected void escapePressed() { closeDialog(); }
private void initComponents()
{
getContentPane().setLayout(new GridBagLayout());
setTitle("Make New View");
setName("");
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) { closeDialog(); }
});
GridBagConstraints gbc;
JLabel jLabel1 = new JLabel("Technology of new cell:");
gbc = new GridBagConstraints();
gbc.gridx = 0; gbc.gridy = 0;
gbc.anchor = GridBagConstraints.WEST;
gbc.insets = new Insets(4, 4, 4, 4);
getContentPane().add(jLabel1, gbc);
newTechnology = new JComboBox();
gbc = new GridBagConstraints();
gbc.gridx = 1; gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(4, 4, 4, 4);
getContentPane().add(newTechnology, gbc);
// show the list of technologies to convert to
oldTech = oldCell.getTechnology();
for(Iterator it = Technology.getTechnologies(); it.hasNext(); )
{
Technology tech = it.next();
if (tech == oldTech) continue;
if (tech.isLayout())
newTechnology.addItem(tech.getTechName());
}
putInSeparateLibrary = new JCheckBox("Place new circuitry in a separate library");
putInSeparateLibrary.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) { sepLibChanged(); }
});
gbc = new GridBagConstraints();
gbc.gridx = 0; gbc.gridy = 1;
gbc.gridwidth = 2;
gbc.anchor = GridBagConstraints.WEST;
gbc.insets = new Insets(4, 4, 1, 4);
getContentPane().add(putInSeparateLibrary, gbc);
jLabel2 = new JLabel("Library for new circuitry:");
gbc = new GridBagConstraints();
gbc.gridx = 0; gbc.gridy = 2;
gbc.anchor = GridBagConstraints.WEST;
gbc.insets = new Insets(1, 20, 4, 4);
getContentPane().add(jLabel2, gbc);
separateLibraryName = new JTextField();
EDialog.makeTextFieldSelectAllOnTab(separateLibraryName);
gbc = new GridBagConstraints();
gbc.gridx = 1; gbc.gridy = 2;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(1, 4, 4, 4);
getContentPane().add(separateLibraryName, gbc);
if (oldTech == Schematics.tech())
{
JLabel jLabel3 = new JLabel("Standard Cell library:");
gbc = new GridBagConstraints();
gbc.gridx = 0; gbc.gridy = 3;
gbc.anchor = GridBagConstraints.WEST;
gbc.insets = new Insets(4, 4, 4, 4);
getContentPane().add(jLabel3, gbc);
standardCellLibrary = new JComboBox();
gbc = new GridBagConstraints();
gbc.gridx = 1; gbc.gridy = 3;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(4, 4, 4, 4);
getContentPane().add(standardCellLibrary, gbc);
// show a list of libraries that can hold standard cells
standardCellLibrary.addItem("");
for(Library lib : Library.getVisibleLibraries())
{
standardCellLibrary.addItem(lib.getName());
}
}
JButton cancel = new JButton("Cancel");
cancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) { closeDialog(); }
});
gbc = new GridBagConstraints();
gbc.gridx = 0; gbc.gridy = 4;
gbc.insets = new Insets(4, 4, 4, 4);
getContentPane().add(cancel, gbc);
JButton ok = new JButton("OK");
ok.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) { ok(); }
});
getRootPane().setDefaultButton(ok);
gbc = new GridBagConstraints();
gbc.gridx = 1; gbc.gridy = 4;
gbc.insets = new Insets(4, 4, 4, 4);
getContentPane().add(ok, gbc);
pack();
}
private void sepLibChanged()
{
jLabel2.setEnabled(putInSeparateLibrary.isSelected());
separateLibraryName.setEditable(putInSeparateLibrary.isSelected());
}
private void ok()
{
String techName = (String)newTechnology.getSelectedItem();
Technology newTech = Technology.findTechnology(techName);
String newLibName = "";
if (putInSeparateLibrary.isSelected()) newLibName = separateLibraryName.getText();
Library stdCellLib = null;
if (oldTech == Schematics.tech())
{
String stdCellLibName = (String)standardCellLibrary.getSelectedItem();
if (stdCellLibName.length() > 0) stdCellLib = Library.findLibrary(stdCellLibName);
}
new MakeLayoutView(oldCell, oldTech, newTech, stdCellLib, context, newLibName);
closeDialog();
}
}
/**
* Class to generate the alternate view of a cell.
*/
public static class MakeLayoutView extends Job
{
private Cell oldCell;
private Technology oldTech, newTech;
private Library stdCellLib;
private VarContext context;
private String newLibName;
private List createdCells;
public MakeLayoutView(Cell oldCell, Technology oldTech, Technology newTech, Library stdCellLib, VarContext context, String newLibName)
{
super("Make Alternate Layout", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.oldCell = oldCell;
this.oldTech = oldTech;
this.newTech = newTech;
this.stdCellLib = stdCellLib;
this.context = context;
this.newLibName = newLibName;
startJob();
}
@Override
public boolean doIt() throws JobException
{
EditingPreferences ep = getEditingPreferences();
// convert the cell and all subcells
Library newLib = Library.getCurrent();
if (newLibName.length() > 0)
{
newLib = Library.findLibrary(newLibName);
if (newLib == null) newLib = Library.newInstance(newLibName, null);
}
createdCells = new ArrayList();
MakeLayoutVisitor visitor = new MakeLayoutVisitor(oldTech, newTech, oldCell.getLibrary(), stdCellLib, createdCells, newLib, ep);
HierarchyEnumerator.enumerateCell(oldCell, context, visitor, Netlist.ShortResistors.ALL);
fieldVariableChanged("createdCells");
return true;
}
public void terminateOK()
{
Cell showCell = null;
for(Cell cell : createdCells)
{
showCell = cell;
}
if (showCell != null)
{
WindowFrame wf = WindowFrame.getCurrentWindowFrame();
if (User.isShowCellsInNewWindow()) wf = null;
if (wf == null) wf = WindowFrame.createEditWindow(showCell);
wf.setCellWindow(showCell, null);
}
}
private static class Info extends HierarchyEnumerator.CellInfo
{
private Map generatedCells;
public Info()
{
generatedCells = new HashMap();
}
}
private static class MakeLayoutVisitor extends HierarchyEnumerator.Visitor
{
private Technology oldTech, newTech;
private Library defaultLib, stdCellLib;
private Map convertedCells;
private StdCellParams stdCell;
private List createdCells;
private Library newLib;
private final EditingPreferences ep;
private MakeLayoutVisitor(Technology oldTech, Technology newTech, Library defaultLib, Library stdCellLib,
List createdCells, Library newLib, EditingPreferences ep)
{
this.ep = ep;
this.oldTech = oldTech;
this.newTech = newTech;
this.defaultLib = defaultLib;
this.stdCellLib = stdCellLib;
this.createdCells = createdCells;
this.newLib = newLib;
convertedCells = new HashMap();
// TODO This code "steals" the intended functionality and diverts it into the gate generator
if (oldTech == Schematics.tech())
{
stdCell = null;
if (newTech == Technology.getCMOS90Technology()) {
stdCell = GateLayoutGenerator.sportParams(ep, false);
} else {
stdCell = GateLayoutGenerator.dividerParams(newTech, ep, false);
}
}
}
public HierarchyEnumerator.CellInfo newCellInfo() { return new Info(); }
private static class Conn
{
private Nodable no;
private PortProto pp;
private Name portName;
private Conn(Nodable no, PortProto pp, Name portName)
{
this.no = no; this.pp = pp; this.portName = portName;
}
}
@Override
public boolean enterCell(HierarchyEnumerator.CellInfo info)
{
Cell oldCell = info.getCell();
if (convertedCells.containsKey(oldCell)) return false;
if (stdCell != null)
{
Info myInfo = (Info)info;
myInfo.generatedCells = GateLayoutGenerator.generateLayoutFromSchematics(
oldCell.getLibrary(), oldCell, info.getContext(), stdCell, true);
}
return true;
}
@Override
public boolean visitNodeInst(Nodable ni, HierarchyEnumerator.CellInfo info)
{
Cell layCell = getLayoutCell(ni, (Info)info);
if (layCell == null) return true;
return false;
}
private Cell getLayoutCell(Nodable no, Info myInfo)
{
if (!no.isCellInstance()) return null;
Cell layCell = null;
Cell subCell = (Cell)no.getProto();
layCell = myInfo.generatedCells.get(no);
if (layCell == null)
layCell = convertedCells.get(subCell);
if (layCell == null)
{
if (oldTech == Schematics.tech())
{
// see if it already exists
for (Iterator it = subCell.getCellGroup().getCells(); it.hasNext(); )
{
Cell c = it.next();
if (c.getView() == View.LAYOUT)
{
layCell = c;
break;
}
}
if (layCell == null && stdCellLib != null && myInfo.isRootCell())
{
layCell = findStandardCell(no);
if (layCell != null)
{
NodeInst ni = no.getNodeInst();
System.out.println("Using standard cell " + layCell.describe(false) + " for " +
ni.getParent().describe(false) + ":" + ni.describe(false));
}
}
if (layCell == null)
{
String searchCellName = subCell.getName() + "{lay}";
layCell = defaultLib.findNodeProto(searchCellName);
}
}
}
if (layCell != null)
{
convertedCells.put(subCell, layCell);
}
return layCell;
}
@Override
public void exitCell(HierarchyEnumerator.CellInfo info)
{
Cell oldCell = info.getCell();
String newCellName = oldCell.getName();
// create the cell
Cell newCell = makeNewCell(newCellName, View.LAYOUT, oldCell, newLib, ep);
if (newCell == null) return;
createdCells.add(newCell);
Map> connections = new HashMap>();
Map convertedNodes = new HashMap();
// create node placement tree and network connections list
PlacerGrid placer = new PlacerGrid();
for (Iterator it = info.getNetlist().getNodables(); it.hasNext(); ) {
Nodable no = it.next();
NodeProto np = null;
if (no.isCellInstance())
{
np = getLayoutCell(no, (Info)info);
if (np == null)
{
System.out.println("Warning: Unable to find layout version of cell "+no.getProto().describe(false));
}
} else
{
np = figureNewNodeProto(no.getNodeInst(), newTech);
}
if (np != null)
{
if (oldTech != Schematics.tech())
{
// layout Conversion
NodeInst newNi = placeLayoutNode(no, np, newCell, info.getContext());
convertedNodes.put(no, newNi);
} else
{
if (np.getFunction().isPin()) continue;
if (np.getFunction() == PrimitiveNode.Function.CONNECT) continue;
if (no.getName().startsWith("fill") || no.getName().startsWith("tfill")) continue;
placer.insert(new Leaf(no, info.getContext(), np, newCell));
// record connections on ports
for (Iterator itp = no.getProto().getPorts(); itp.hasNext(); )
{
PortProto pp = itp.next();
Name ppname = pp.getNameKey();
for (int i=0; i list = connections.get(net);
if (list == null)
{
list = new ArrayList();
connections.put(net, list);
}
// if port on same node already connects to this network, skip it
boolean add = true;
for (Conn aconn : list)
{
if (aconn.no == conn.no) { add = false; break; }
}
if (add) list.add(conn);
}
}
}
}
}
if (oldTech == Schematics.tech())
{
// place all new nodes
placer.place(this, convertedNodes);
// create rats nest of connections
ArcProto ratArc = Generic.tech().unrouted_arc;
for (Iterator it = info.getNetlist().getNetworks(); it.hasNext(); )
{
Network network = it.next();
List list = connections.get(network);
if (list == null) continue;
if (list.size() == 0) continue;
Conn conn = list.get(0);
PortInst pi = getLayoutPortInst(conn, convertedNodes);
if (pi == null)
{
System.out.println("Cannot find port "+conn.portName+" on "+conn.no.getName()+" in cell "+newCell.describe(false));
continue;
}
String exportName = null;
Export e = null;
Iterator eIt = network.getExports();
if (eIt.hasNext())
{
e = eIt.next();
exportName = network.getName();
}
for (int i=1; i convertedNodes)
{
NodeInst layNi = convertedNodes.get(schConn.no);
if (layNi == null) return null;
PortInst pi = layNi.findPortInst(schConn.portName.toString());
if (pi != null) return pi;
// if each has only 1 port, they match
int numNewPorts = layNi.getProto().getNumPorts();
if (numNewPorts == 0) return null;
if (numNewPorts == 1)
{
return layNi.getPortInst(0);
}
if (schConn.no.getNodeInst().getFunction().isTransistor())
{
if (schConn.portName.toString().equals("g")) return layNi.getTransistorGatePort();
if (schConn.portName.toString().equals("s")) return layNi.getTransistorSourcePort();
if (schConn.portName.toString().equals("d")) return layNi.getTransistorDrainPort();
}
// associate by position in port list
for (int i=0; i convertedCells,
Map convertedNodes)
{
// // first convert the nodes
// for(Iterator it = oldCell.getNodes(); it.hasNext(); )
// {
// NodeInst ni = it.next();
// // handle sub-cells
// if (ni.isCellInstance())
// {
// Cell newCellType = (Cell)convertedCells.get((Cell)ni.getProto());
// if (newCellType == null)
// {
// System.out.println("No equivalent cell for " + ni.getProto());
// continue;
// }
// placeLayoutNode(ni, newCellType, newCell, VarContext.globalContext);
// continue;
// }
//
// // handle primitives
// if (ni.getProto() == Generic.tech.cellCenterNode) continue;
// NodeProto newNp = figureNewNodeProto(ni, newTech);
// if (newNp != null)
// placeLayoutNode(ni, newNp, newCell, VarContext.globalContext);
// }
/*
* for each arc in cell, find the ends in the new technology, and
* make a new arc to connect them in the new cell
*/
for(Iterator it = oldCell.getArcs(); it.hasNext(); )
{
ArcInst ai = it.next();
// get the nodes and ports on the two ends of the arc
NodeInst oldHeadNi = ai.getHeadPortInst().getNodeInst();
NodeInst oldTailNi = ai.getTailPortInst().getNodeInst();
NodeInst newHeadNi = convertedNodes.get(oldHeadNi);
NodeInst newTailNi = convertedNodes.get(oldTailNi);
if (newHeadNi == null || newTailNi == null) continue;
PortProto oldHeadPp = ai.getHeadPortInst().getPortProto();
PortProto oldTailPp = ai.getTailPortInst().getPortProto();
PortProto newHeadPp = convertPortName(oldHeadNi, newHeadNi, oldHeadPp.getNameKey());
PortProto newTailPp = convertPortName(oldTailNi, newTailNi, oldTailPp.getNameKey());
if (newHeadPp == null || newTailPp == null) continue;
// compute arc type and see if it is acceptable
ArcProto newAp = figureNewArcProto(ai.getProto(), newTech, newHeadPp, newTailPp);
// determine new arc width
boolean fixAng = ai.isFixedAngle();
double newWid = 0;
if (newAp == Generic.tech().universal_arc) fixAng = false; else
{
double defwid = ai.getProto().getDefaultLambdaBaseWidth(ep);
double curwid = ai.getLambdaBaseWidth();
newWid = newAp.getDefaultLambdaBaseWidth(ep) * curwid / defwid;
if (!(newWid > 0)) newWid = newAp.getDefaultLambdaBaseWidth(ep);
}
// find the endpoints of the arc
Point2D pHead = ai.getHeadLocation();
Point2D pTail = ai.getTailLocation();
PortInst newHeadPi = newHeadNi.findPortInstFromProto(newHeadPp);
PortInst newTailPi = newTailNi.findPortInstFromProto(newTailPp);
Poly newHeadPoly = newHeadPi.getPoly();
Poly newTailPoly = newTailPi.getPoly();
// see if the new arc can connect without end adjustment
if (!newHeadPoly.contains(pHead) || !newTailPoly.contains(pTail))
{
// arc cannot be run exactly ... presume port centers
if (!newHeadPoly.contains(pHead)) pHead = new EPoint(newHeadPoly.getCenterX(), newHeadPoly.getCenterY());
if (fixAng)
{
// old arc was fixed-angle so look for a similar-angle path
Rectangle2D headBounds = newHeadPoly.getBounds2D();
Rectangle2D tailBounds = newTailPoly.getBounds2D();
Point2D [] newPoints = GenMath.arcconnects(ai.getDefinedAngle(), headBounds, tailBounds);
if (newPoints != null)
{
pHead = new EPoint(newPoints[0].getX(), newPoints[0].getY());
pTail = new EPoint(newPoints[1].getX(), newPoints[1].getY());
}
}
}
// create the new arc
ArcInst newAi = ArcInst.makeInstanceBase(newAp, ep, newWid, newHeadPi, newTailPi, pHead, pTail, ai.getName());
if (newAi == null)
{
System.out.println("Cell " + newCell.describe(true) + ": can't run " + newAp + " from " +
newHeadNi + " " + newHeadPp + " at (" + pHead.getX() + "," + pHead.getY() + ") to " +
newTailNi + " " + newTailPp + " at (" + pTail.getX() + "," + pTail.getY() + ")");
continue;
}
newAi.copyPropertiesFrom(ai);
if (newAp == Generic.tech().universal_arc)
{
ai.setFixedAngle(false);
ai.setRigid(false);
}
}
}
/**
* Method to determine the equivalent prototype in technology "newtech" for
* node prototype "oldnp".
*/
private NodeProto figureNewNodeProto(NodeInst oldni, Technology newTech)
{
// easy translation if complex or already in the proper technology
NodeProto oldNp = oldni.getProto();
if (oldni.isCellInstance() || oldNp.getTechnology() == newTech) return oldNp;
// if this is a layer node, check the layer functions
PrimitiveNode.Function type = oldni.getFunction();
if (oldni.getParent().isSchematic() && type.isTransistor())
{
for (Iterator it = newTech.getNodes(); it.hasNext(); )
{
PrimitiveNode node = it.next();
if (type == node.getFunction()) return node;
}
PrimitiveNode.Function threePort = type.make3PortTransistor();
for (Iterator it = newTech.getNodes(); it.hasNext(); )
{
PrimitiveNode node = it.next();
if (threePort == node.getFunction()) return node;
}
}
if (type == PrimitiveNode.Function.NODE)
{
// get the polygon describing the first box of the old node
PrimitiveNode np = (PrimitiveNode)oldNp;
Technology.NodeLayer [] nodeLayers = np.getNodeLayers();
Layer layer = nodeLayers[0].getLayer();
Layer.Function fun = layer.getFunction();
// now search for that function in the other technology
for(Iterator it = newTech.getNodes(); it.hasNext(); )
{
PrimitiveNode oNp = it.next();
if (oNp.getFunction() != PrimitiveNode.Function.NODE) continue;
Technology.NodeLayer [] oNodeLayers = oNp.getNodeLayers();
Layer oLayer = oNodeLayers[0].getLayer();
Layer.Function oFun = oLayer.getFunction();
if (fun == oFun) return oNp;
}
}
// see if one node in the new technology has the same function
int i = 0;
PrimitiveNode rNp = null;
for(Iterator it = newTech.getNodes(); it.hasNext(); )
{
PrimitiveNode np = it.next();
if (np.getFunction() == type)
{
rNp = np; i++;
}
}
if (i == 1) return rNp;
// if there are too many matches, determine which is proper from arcs
if (i > 1)
{
// see if this node has equivalent arcs
PrimitiveNode pOldNp = (PrimitiveNode)oldNp;
PrimitivePort pOldPp = pOldNp.getPort(0);
ArcProto [] oldConnections = pOldPp.getConnections();
for(Iterator it = newTech.getNodes(); it.hasNext(); )
{
PrimitiveNode pNewNp = it.next();
if (pNewNp.getFunction() != type) continue;
PrimitivePort pNewPp = pNewNp.getPort(0);
ArcProto [] newConnections = pNewPp.getConnections();
boolean oldMatches = true;
for(int j=0; j= -450) break;
if (averageDelta <= 450) or = or.concatenate(Orientation.R); else
or = or.concatenate(Orientation.RRR);
}
}
} else
{
Cell np = (Cell)newNp;
Rectangle2D bounds = np.getBounds();
newXSize = bounds.getWidth();
newYSize = bounds.getHeight();
}
// create the node
NodeInst newNi = NodeInst.makeInstance(newNp, ep, ni.getAnchorCenter(), newXSize, newYSize, newCell, or, no.getName(), ni.getTechSpecific());
if (newNi == null)
{
System.out.println("Could not create " + newNp + " in " + newCell);
return null;
}
newNi.copyStateBits(ni);
if (!no.getParent().isSchematic())
newNi.copyVarsFrom(ni);
// re-export any ports on the node
for(Iterator it = ni.getExports(); it.hasNext(); )
{
Export e = it.next();
for (int i=0; i= Math.abs(yDist))
{
if (xDist < 0) return Location.LEFT;
return Location.RIGHT;
}
if (yDist < 0) return Location.BELOW;
return Location.ABOVE;
}
protected Point2D getCenter(boolean lay) {
Rectangle2D bounds;
if (lay) bounds = getLayBounds();
else bounds = getSchBounds();
if (bounds == null) return null;
return new EPoint(bounds.getCenterX(), bounds.getCenterY());
}
protected Rectangle2D getLayBounds() {
if (node == null) return null;
Rectangle2D bounds = node.getLayBounds();
if (aboveNode != null) bounds = bounds.createUnion(aboveNode.getLayBounds());
if (belowNode != null) bounds = bounds.createUnion(belowNode.getLayBounds());
if (leftNode != null) bounds = bounds.createUnion(leftNode.getLayBounds());
if (rightNode != null) bounds = bounds.createUnion(rightNode.getLayBounds());
return bounds;
}
protected Rectangle2D getSchBounds() {
if (node == null) return null;
Rectangle2D bounds = node.getSchBounds();
if (aboveNode != null) bounds = bounds.createUnion(aboveNode.getSchBounds());
if (belowNode != null) bounds = bounds.createUnion(belowNode.getSchBounds());
if (leftNode != null) bounds = bounds.createUnion(leftNode.getSchBounds());
if (rightNode != null) bounds = bounds.createUnion(rightNode.getSchBounds());
return bounds;
}
protected void place(MakeLayoutVisitor visitor, Map convertedNodes) {
if (node == null) return;
node.place(visitor, convertedNodes);
if (aboveNode != null) placeRelative(aboveNode, node, Location.ABOVE, visitor, convertedNodes);
if (belowNode != null) placeRelative(belowNode, node, Location.BELOW, visitor, convertedNodes);
if (leftNode != null) placeRelative(leftNode, node, Location.LEFT, visitor, convertedNodes);
if (rightNode != null) placeRelative(rightNode, node, Location.RIGHT, visitor, convertedNodes);
}
private void placeRelative(PlacerGrid placeNode, PlacerGrid refNode, Location schRelLoc,
MakeLayoutVisitor visitor, Map convertedNodes) {
placeNode.place(visitor, convertedNodes);
Location layRelLoc = getRelativeLocation(placeNode.getCenter(true), refNode.getCenter(true));
if (schRelLoc != layRelLoc || placeNode.getLayBounds().intersects(refNode.getLayBounds())) {
// move placed node to abut to reference node
abut(placeNode, refNode, schRelLoc);
}
}
private void abut(PlacerGrid abutNode, PlacerGrid refNode, Location relativeLocation) {
double dx = 0;
double dy = 0;
Rectangle2D referenceBounds = refNode.getLayBounds();
Rectangle2D niBounds = abutNode.getLayBounds();
if (relativeLocation == Location.RIGHT) {
dx = referenceBounds.getMaxX() - niBounds.getMinX();
} else if (relativeLocation == Location.LEFT) {
dx = referenceBounds.getMinX() - niBounds.getMaxX();
} else if (relativeLocation == Location.ABOVE) {
dy = referenceBounds.getMaxY() - niBounds.getMinY();
} else if (relativeLocation == Location.BELOW) {
dy = referenceBounds.getMinY() - niBounds.getMaxY();
}
if (dx != 0 || dy != 0) {
abutNode.move(dx, dy);
}
}
protected void move(double dx, double dy) {
node.move(dx, dy);
if (aboveNode != null) aboveNode.move(dx, dy);
if (belowNode != null) belowNode.move(dx, dy);
if (leftNode != null) leftNode.move(dx, dy);
if (rightNode != null) rightNode.move(dx, dy);
}
protected void print(int indent) {
}
public void prindent(int ident) {
for (int i=0; i convertedNodes) {
layNi = visitor.placeLayoutNode(schNo, layNp, newCell, context);
convertedNodes.put(schNo, layNi);
}
protected void move(double dx, double dy) {
layNi.modifyInstance(dx, dy, 0, 0, Orientation.IDENT);
}
protected void print(int indent) {
prindent(indent);
System.out.println("node "+schNo.getName()+" at "+getCenter(false));
}
}
/**
* Method to determine the equivalent prototype in technology "newTech" for
* node prototype "oldnp".
*/
private ArcProto figureNewArcProto(ArcProto oldAp, Technology newTech, PortProto headPp, PortProto tailPp)
{
// generic arcs stay the same
if (oldAp.getTechnology() == Generic.tech()) return oldAp;
// schematic wires become universal arcs
if (oldAp != Schematics.tech().wire_arc)
{
// determine the proper association of this node
ArcProto.Function type = oldAp.getFunction();
for(Iterator it = newTech.getArcs(); it.hasNext(); )
{
ArcProto newAp = it.next();
if (newAp.getFunction() == type) return newAp;
}
}
// cannot figure it out from the function: find anything that can connect
Set possibleArcs = new HashSet();
ArcProto [] headArcs = headPp.getBasePort().getConnections();
ArcProto [] tailArcs = tailPp.getBasePort().getConnections();
for(int i=0; i < headArcs.length; i++)
{
if (headArcs[i].getTechnology() == Generic.tech()) continue;
for(int j=0; j < tailArcs.length; j++)
{
if (tailArcs[j].getTechnology() == Generic.tech()) continue;
if (headArcs[i] != tailArcs[j]) continue;
possibleArcs.add(headArcs[i]);
break;
}
}
for(Iterator it = newTech.getArcs(); it.hasNext(); )
{
ArcProto ap = it.next();
if (possibleArcs.contains(ap)) return ap;
}
System.out.println("No equivalent arc for " + oldAp);
return Generic.tech().universal_arc;
}
/**
* Method to determine the port to use on node "newni" assuming that it should
* be the same as port "oldPp" on equivalent node "ni"
*/
/* private PortProto convertPortProto(NodeInst ni, NodeInst newNi, PortProto oldPp)
{
if (newNi.isCellInstance())
{
// cells can associate by comparing names
PortProto pp = newNi.getProto().findPortProto(oldPp.getName());
if (pp != null) return pp;
// System.out.println("Cannot find export " + oldPp.getName() + " in " + newNi.getProto());
return null;
}
// if each has only 1 port, they match
int numNewPorts = newNi.getProto().getNumPorts();
if (numNewPorts == 0) return null;
if (numNewPorts == 1)
{
return newNi.getProto().getPort(0);
}
// associate by position in port list
Iterator oldPortIt = ni.getProto().getPorts();
Iterator newPortIt = newNi.getProto().getPorts();
while (oldPortIt.hasNext() && newPortIt.hasNext())
{
PortProto pp = oldPortIt.next();
PortProto newPp = newPortIt.next();
if (pp == oldPp) return newPp;
}
// special case again: one-port capacitors are OK
PrimitiveNode.Function oldFun = ni.getFunction();
PrimitiveNode.Function newFun = newNi.getFunction();
if (oldFun == PrimitiveNode.Function.CAPAC && newFun == PrimitiveNode.Function.ECAPAC) return newNi.getProto().getPort(0);
// association has failed: assume the first port
System.out.println("No port association between " + ni.getProto() + ", "
+ oldPp + " and " + newNi.getProto());
return newNi.getProto().getPort(0);
}*/
/**
* Method to determine the port to use on node "newNi" assuming that it should
* be the same as port "portName" on equivalent node "ni"
*/
private PortProto convertPortName(NodeInst ni, NodeInst newNi, Name portName) {
if (newNi.isCellInstance()) {
PortProto pp = newNi.getProto().findPortProto(portName);
if (pp == null)
System.out.println("Cannot find export " + portName + " in " + newNi.getProto());
return pp;
}
// if each has only 1 port, they match
int numNewPorts = newNi.getProto().getNumPorts();
if (numNewPorts == 0) return null;
if (numNewPorts == 1)
{
return newNi.getProto().getPort(0);
}
// associate by position in port list
PortProto pp = ni.getProto().findPortProto(portName);
if (pp != null) {
int i = 0;
for (i=0; i essentialVars = getVariables(essentialIcon);
// now find a cell with just that essential icon
Map> possibleNodes = new HashMap>();
for(Iterator it = stdCellLib.getCells(); it.hasNext(); )
{
Cell stdCell = it.next();
NodeInst thisEI = getEssentialContent(stdCell);
if (thisEI != null && thisEI.getProto() == essentialIcon.getProto())
{
// find equivalent layout cell
for(Iterator cIt = stdCell.getCellGroup().getCells(); cIt.hasNext(); )
{
Cell layCell = cIt.next();
if (layCell.getView() == View.LAYOUT)
possibleNodes.put(thisEI, getVariables(thisEI)); // return layCell;
}
}
}
if (possibleNodes.size() == 0) return null;
double bestParamDist = Double.MAX_VALUE;
NodeInst bestNi = null;
for(NodeInst thisEI : possibleNodes.keySet())
{
Map thisVars = possibleNodes.get(thisEI);
double paramDist = computeParameterDistance(essentialVars, thisVars);
if (paramDist < bestParamDist)
{
bestParamDist = paramDist;
bestNi = thisEI;
}
}
// determine the layout cell with this node
for(Iterator cIt = bestNi.getParent().getCellGroup().getCells(); cIt.hasNext(); )
{
Cell layCell = cIt.next();
if (layCell.getView() == View.LAYOUT) return layCell;
}
return null;
}
/**
* Method to find the "essential" node in a cell.
* There must be just one such node, ignoring pins, contacts, etc.
* @param cell the Cell to search.
* @return the essential NodeInst in the Cell (null if none).
*/
private NodeInst getEssentialContent(Cell cell)
{
NodeInst essentialContent = null;
for(Iterator it = cell.getNodes(); it.hasNext(); )
{
NodeInst ni = it.next();
if (ni.isIconOfParent()) continue;
PrimitiveNode.Function fun = ni.getFunction();
if (fun.isPin()) continue;
if (fun == PrimitiveNode.Function.CONNECT) continue;
if (fun == PrimitiveNode.Function.ART) continue;
if (essentialContent != null) { essentialContent = null; break; }
essentialContent = ni;
}
return essentialContent;
}
/**
* Method to create a map of all variables and values on a given NodeInst.
* @param ni the NodeInst to examine.
* @return a Map from String variable names to Double variable values.
*/
private Map getVariables(NodeInst ni)
{
Map vars = new HashMap();
for(Iterator it = ni.getParametersAndVariables(); it.hasNext(); )
{
Variable var = it.next();
if (!var.isDisplay()) continue;
String value = null; // var.describe(-1, VarContext.globalContext, ni);
if (var.isCode())
{
// special case for code: it is a string, the type applies to the result
Object val = null;
try {
val = VarContext.globalContext.evalVarRecurse(var, ni);
value = val.toString();
} catch (VarContext.EvalException e) {}
} else
{
value = var.getPureValue(-1);
}
if (TextUtils.isANumber(value))
{
Double v = new Double(TextUtils.atof(value));
vars.put(var.getKey().getName(), v);
}
}
return vars;
}
/**
* Method to determine the distance between two sets of parameters.
* @param pars1 a map of parameter name and value for the first set of parameters.
* @param pars2 a map of parameter name and value for the second set of parameters.
* @return the distance between the parameter values (smaller numbers are closer).
*/
private double computeParameterDistance(Map pars1, Map pars2)
{
double dist = 0;
for(String par1 : pars1.keySet())
{
Double val1 = pars1.get(par1);
Double val2 = pars2.get(par1);
if (val2 == null) continue;
dist += Math.abs(val1.doubleValue() - val2.doubleValue());
}
return dist;
}
}
}
}
| | | | | | | | | | | | | | | |