com.sun.electric.database.ImmutableLayoutHierarchyEnumerator Maven / Gradle / Ivy
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: HierarchyEnumerator.java
*
* Copyright (c) 2003, 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.database;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Export;
import com.sun.electric.database.hierarchy.Nodable;
import com.sun.electric.database.id.PortProtoId;
import com.sun.electric.database.network.Global;
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.PortProto;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.ArcInst;
import com.sun.electric.database.topology.Geometric;
import com.sun.electric.database.variable.VarContext;
import com.sun.electric.tool.Job;
import com.sun.electric.util.TextUtils;
import com.sun.electric.util.math.FixpTransform;
import java.awt.geom.Rectangle2D;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/** The HierarchyEnumerator can help programs that need to "flatten"
* the design hierarchy. Examples of such programs include the logical
* effort engine and routers.
*
* The HierarchyEnumerator performs a recursive descent of
* the "completely expanded" design hierarchy. The HierarchyEnumerator
* brings the Visitor along with it during the excursion.
* The HierarchyEnumerator doesn't build a flattened data structure,
* that's the prerogative of the Visitor. The HierarchyEnumerator simply
* invokes Visitor methods for each Cell instance and NodeInst.
*
*
The following example illustrates the notion of "completely
* expanded". Suppose the root Cell instantiates Cell A twice, and
* Cell A instantiates Cell B twice. Then the HierarchyEnumerator
* visits two instances of Cell A and four instances of Cell B.
*/
public final class ImmutableLayoutHierarchyEnumerator {
// /** Stores the information necessary to generate an instance name for a Part
// * It is sometimes important not to store the instance name as a String.
// * When I stored instance names as strings in NCC profiles indicated that
// * almost 50% of the storage space was used in these strings and 70% of the
// * execution time was spent generating these Strings!!! */
// public static abstract class NameProxy implements Serializable {
//
// private VarContext context;
// private String sep;
//
// private String makePath(VarContext context, String sep) {
// String path = context.getInstPath(sep);
// if (!path.equals("")) {
// path += sep;
// }
// return path;
// }
//
// protected NameProxy(VarContext context, String sep) {
// this.context = context;
// this.sep = sep;
// }
//
// abstract public String leafName();
//
// abstract public Cell leafCell();
//
// public VarContext getContext() {
// return context;
// }
//
// public String toString() {
// return makePath(context, sep) + leafName();
// }
//
// public String toString(int numRemoveParents) {
// VarContext localContext = context.removeParentContext(numRemoveParents);
// String ret = makePath(localContext, sep) + leafName();
// return ret;
// }
// }
//
// public static class NetNameProxy extends NameProxy {
//
// static final long serialVersionUID = 0;
// private Network net;
//
// public String leafName() {
// Iterator it = net.getNames();
// if (it.hasNext()) {
// return it.next();
// }
// return "netIndex" + net.getNetIndex();
// }
//
// public Iterator leafNames() {
// return net.getNames();
// }
//
// public NetNameProxy(VarContext context, String sep, Network net) {
// super(context, sep);
// this.net = net;
// }
//
// public Cell leafCell() {
// return net.getParent();
// }
//
// public Network getNet() {
// return net;
// }
// }
//
// public static class NodableNameProxy extends NameProxy {
//
// static final long serialVersionUID = 0;
// private Nodable nodable;
//
// public String leafName() {
// return nodable.getName();
// }
//
// public NodableNameProxy(VarContext context, String sep, Nodable node) {
// super(context, sep);
// this.nodable = node;
// }
//
// public Cell leafCell() {
// return nodable.getParent();
// }
//
// public Nodable getNodable() {
// return nodable;
// }
// }
// --------------------- private data ------------------------------
private Visitor visitor;
private boolean caching;
private int curNetId = 0;
private int cellCnt = 0; // For statistics
private int instCnt = 0; // For statistics
private Map netIdToNetDesc =
new HashMap();
private HashMap cellExternalIds = new HashMap();
private static void error(boolean pred, String msg) {
Job.error(pred, msg);
}
// Prevent anyone from instantiating HierarchyEnumerator.
private ImmutableLayoutHierarchyEnumerator() {
}
private int[] getExternalIds(Cell cell, Netlist netlist) {
int[] externalIds = cellExternalIds.get(cell);
if (externalIds != null) {
return externalIds;
}
externalIds = new int[netlist.getNumExternalNetworks()];
cellExternalIds.put(cell, externalIds);
return externalIds;
}
//private int nextNetID() { return netIdToNetDesc.size(); }
private int[] numberNets(Cell cell, Netlist netlist,
int[][] portNdxToNetIDs, CellInfo info) {
int numNets = netlist.getNumNetworks();
int[] externalIds = getExternalIds(cell, netlist);
int[] netNdxToNetID = new int[numNets];
int baseId = curNetId;
Arrays.fill(externalIds, -1);
if (portNdxToNetIDs != null) {
assert portNdxToNetIDs.length == cell.getNumPorts() + 1;
Global.Set globals = netlist.getGlobals();
assert portNdxToNetIDs[0].length == globals.size();
for (int i = 0; i < globals.size(); i++) {
Global global = globals.get(i);
int netIndex = netlist.getNetwork(global).getNetIndex();
externalIds[netIndex] = portNdxToNetIDs[0][i];
}
for (int i = 0, numPorts = cell.getNumPorts(); i < numPorts; i++) {
Export export = cell.getPort(i);
int[] ids = portNdxToNetIDs[i + 1];
assert ids.length == export.getNameKey().busWidth();
for (int j = 0; j < ids.length; j++) {
int netIndex = netlist.getNetwork(export, j).getNetIndex();
externalIds[netIndex] = ids[j];
}
}
for (int i = 0; i < externalIds.length; i++) {
assert externalIds[i] >= 0;
}
baseId -= externalIds.length;
}
for (int i = 0; i < numNets; i++) {
Network net = netlist.getNetwork(i);
int localId = i;
assert baseId + localId <= curNetId;
if (baseId + localId == curNetId) {
if (portNdxToNetIDs == null && localId < externalIds.length) {
externalIds[localId] = localId;
}
assert curNetId == baseId + localId;
netIdToNetDesc.put(curNetId++, new NetDescription(net, info));
} else if (localId >= externalIds.length || portNdxToNetIDs == null) {
NetDescription nd = netIdToNetDesc.get(baseId + localId);
int cmp = !net.isUsernamed() ? 1 : nd.net.isUsernamed() ? 0 : -1;
if (cmp == 0 && net.isExported() != nd.net.isExported()) {
cmp = net.isExported() ? -1 : 1;
}
if (cmp == 0) {
cmp = TextUtils.STRING_NUMBER_ORDER.compare(net.getName(), nd.net.getName());
}
if (cmp < 0) {
nd.net = net;
}
}
int id = localId < externalIds.length ? externalIds[localId] : baseId + localId;
netNdxToNetID[i] = id;
}
return netNdxToNetID;
}
private static int[] getGlobalNetIDs(Nodable no, Netlist netlist, int[] netNdxToNetID) {
Global.Set gs = netlist.getNetlist(no).getGlobals();
int[] netIDs = new int[gs.size()];
for (int i = 0; i < gs.size(); i++) {
int netIndex = netlist.getNetwork(no, gs.get(i)).getNetIndex();
int netID = netNdxToNetID[netIndex];
error(netID < 0, "no netID for net");
netIDs[i] = netID;
}
return netIDs;
}
private static int[] getPortNetIDs(Nodable no, PortProto pp,
Netlist netlist, int[] netNdxToNetID) {
int busWidth = pp.getNameKey().busWidth();
int[] netIDs = new int[busWidth];
for (int j = 0; j < busWidth; j++) {
Network net = netlist.getNetwork(no, pp, j);
error(net == null, "no network for net " + pp.getNameKey());
int netIndex = net.getNetIndex();
int netID = netNdxToNetID[netIndex];
error(netID < 0, "no netID for net " + pp.getNameKey());
netIDs[j] = netID;
}
return netIDs;
}
private static int[][] buildPortMap(Netlist netlist, Nodable ni,
int[] netNdxToNetID) {
Cell cell = (Cell) ni.getProto();
int numPorts = cell.getNumPorts();
int[][] portNdxToNetIDs = new int[numPorts + 1][];
portNdxToNetIDs[0] = getGlobalNetIDs(ni, netlist, netNdxToNetID);
for (int i = 0; i < numPorts; i++) {
PortProto pp = cell.getPort(i);
portNdxToNetIDs[i + 1] = getPortNetIDs(ni, pp, netlist, netNdxToNetID);
}
return portNdxToNetIDs;
}
/** portNdxToNetIDs translates an Export's index to an array of NetIDs */
private void enumerateCell(Nodable parentInst, Cell cell,
VarContext context, Netlist netlist,
int[][] portNdxToNetIDs,
FixpTransform xformToRoot, CellInfo parent, Rectangle2D bounds) {
CellInfo info = visitor.newCellInfo();
int firstNetID = curNetId;
int[] netNdxToNetID = numberNets(cell, netlist, portNdxToNetIDs, info);
int lastNetIDPlusOne = curNetId;
cellCnt++;
info.init(parentInst, cell, context, netlist, netNdxToNetID,
portNdxToNetIDs, xformToRoot, netIdToNetDesc, parent);
boolean enumInsts = visitor.enterCell(info);
if (!enumInsts) {
return;
}
if (bounds != null) {
for (Iterator it = cell.searchIterator(bounds); it.hasNext();) {
Geometric geom = it.next();
if (!(geom instanceof NodeInst)) {
continue;
}
NodeInst ni = (NodeInst) geom;
visitThisNode(ni, context, netlist, info, netNdxToNetID, xformToRoot);
}
} else {
for (Iterator it = netlist.getNodables(); it.hasNext();) {
Nodable ni = it.next();
visitThisNode(ni, context, netlist, info, netNdxToNetID, xformToRoot);
}
}
visitor.exitCell(info);
// release storage associated with VarContext variable cache
context.deleteVariableCache();
// remove entries in netIdToNetDesc that we'll never use again
for (int i = firstNetID; i < lastNetIDPlusOne; i++) {
netIdToNetDesc.remove(i);
}
}
private void visitThisNode(Nodable ni, VarContext context, Netlist netlist, CellInfo info,
int[] netNdxToNetID, FixpTransform xformToRoot) {
instCnt++;
boolean descend = visitor.visitNodeInst(ni, info);
NodeProto np = ni.getProto();
if (descend && ni.isCellInstance() && !((Cell) np).isIcon()) {
int[][] portNmToNetIDs2 = buildPortMap(netlist, ni, netNdxToNetID);
FixpTransform xformToRoot2 = xformToRoot;
if (ni instanceof NodeInst) {
// add transformation from lower level
xformToRoot2 = new FixpTransform(xformToRoot);
xformToRoot2.concatenate(((NodeInst) ni).rotateOut());
xformToRoot2.concatenate(((NodeInst) ni).translateOut());
}
enumerateCell(ni, (Cell) np,
caching ? context.pushCaching(ni) : context.push(ni),
netlist.getNetlist(ni),
portNmToNetIDs2, xformToRoot2, info, null);
}
}
// Set up everything for the root cell and then initiate the
// hierarchical traversal.
private void doIt(Cell root, VarContext context, Netlist netlist,
Visitor visitor, boolean cache, Rectangle2D bounds) {
this.visitor = visitor;
this.caching = cache;
if (context == null) {
context = VarContext.globalContext;
}
int[][] exportNdxToNetIDs = null;
enumerateCell(null, root, context, netlist, exportNdxToNetIDs,
new FixpTransform(), null, bounds);
// System.out.println("A total of: " + curNetId + " nets were numbered");
// System.out.println("A total of: " + cellCnt + " Cells were visited");
// System.out.println("A total of: " + instCnt + " NodeInsts were visited");
}
// ------------------------ public types ---------------------------
/** Perform useful work while the HierarchyEnumerator enumerates
* the design. Whereas the HierarchyEnumerator is responsible for
* enumerating every Cell and NodeInst in the flattened design,
* the Visitor object is responsible for performing useful work
* during the enumeration.
*
* The HierarchyEnumerator performs a recursive descent of the
* design hierarchy starting with the root Cell. When the
* HierarchyEnumerator enters a Cell instance it calls the Visitor's
* enterCell() method to let the Visitor know that it's just started
* working on a new Cell instance. Then the HierarchyEnumerator calls
* the Visitor's visitNodeInst() method for each NodeInst in that
* Cell. Finally, after all the NodeInsts have been visited, the
* HierarchyEnumerator calls the Visitor's exitCell() method to
* inform the Visitor that the HierarchyEnumerator is done with that
* Cell.
*
* The Visitor's visitNodeInst() method controls whether the
* HierarchyEnumerator descends recursively into the Cell
* instantiated by that NodeInst. If the visitNodeInst() method
* returns true, then the HierarchyEnumerator enumerates the contents
* of that NodeInst's child Cell before it continues enumerating the
* NodeInsts of the current Cell.
*/
public static abstract class Visitor {
/** A hook to allow the user to add additional information to
* a CellInfo. The newCellInfo method is a "Factory"
* method. If the user wishes to record additional application
* specific information for each Cell, the user should extend
* the CellInfo class and then override newCellInfo to return
* an instance of that derived class. */
public CellInfo newCellInfo() {
return new CellInfo();
}
/** The HierarchyEnumerator is about to begin enumerating the
* contents of a new Cell instance. That instance has just
* become the new "current" Cell instance.
* @param info information about the Cell instance being
* enumerated
* @return a boolean indicating if the HierarchyEnumerator
* should enumerate the contents of the current Cell. True
* means enumerate the current cell */
public abstract boolean enterCell(CellInfo info);
/** The HierarchyEnumerator has finished enumerating the
* contents of the current Cell instance. It is about to leave
* it, never to return. The CellInfo associated with the
* current Cell instance is about to be abandoned.
* @param info information about the Cell instance being
* enumerated */
public abstract void exitCell(CellInfo info);
/** The HierarchyEnumerator is visiting Nodable ni.
* @param ni the Nodable that HierarchyEnumerator is visiting.
* @return a boolean indicating whether or not the
* HierarchyEnumerator should expand the Cell instantiated by
* ni. True means expand. If ni instantiates a PrimitiveNode
* then the return value is ignored by the
* HierarchyEnumerator. */
public abstract boolean visitNodeInst(Nodable ni, CellInfo info);
/** Using visitNodeInst implements a Top-Down traversal. If one
* wishes to implement Bottom-Up traversal, use this method instead,
* or in conjunction with visitNodeInst. */
//public abstract void visitNodeInstBottomUp(Nodable ni, CellInfo info);
}
/** The NetDescription object provides a Network and the level of
* hierarchy in which the Network occurs. The visitor can use
* NetDescription to formulate, for example, the name of
* the net */
public static class NetDescription {
private Network net;
private CellInfo info;
NetDescription(Network net, CellInfo info) {
this.net = net;
this.info = info;
}
public Network getNet() {
return net;
}
public CellInfo getCellInfo() {
return info;
}
}
/** The CellInfo object is used to pass information to the Visitor
* during the enumeration. The CellInfo object contains many methods
* that describe the Cell currently being enumerated and the state
* of the enumeration.
*
* The HierarchyEnumerator creates a new CellInfo for a Cell
* instance just before it begins enumerating the contents of that
* Cell instance. The HierarchyEnumerator abandons the CellInfo once
* it is done enumerating the contents of that Cell instance. Once
* the CellInfo is abandoned the garbage collector may reclaim the
* CellInfo's storage.
*
* Each CellInfo has a reference to the CellInfo of the parent of
* the current Cell instance. Thus the Visitor is able to get
* information about all the ancestors of the current Cell
* instance.
*
* In most cases, the user will need to store additional
* information in the CellInfo. In those cases the user should
* extend the CellInfo class and override the Visitor.newCellInfo()
* method to return an instance of the derived class.
*/
public static class CellInfo {
private Nodable parentInst;
private Cell cell;
private CellTree cellTree;
private VarContext context;
private Netlist netlist;
private int[] netNdxToNetID;
private int[][] exportNdxToNetIDs;
private FixpTransform xformToRoot;
private Map netIdToNetDesc;
private CellInfo parentInfo;
// package private
void init(Nodable parentInst, Cell cell, VarContext context, Netlist netlist,
int[] netToNetID, int[][] exportNdxToNetIDs,
FixpTransform xformToRoot, Map netIdToNetDesc,
CellInfo parentInfo) {
this.parentInst = parentInst;
this.cell = cell;
this.cellTree = cell.tree();
this.context = context;
this.netlist = netlist;
this.netNdxToNetID = netToNetID;
this.exportNdxToNetIDs = exportNdxToNetIDs;
this.xformToRoot = xformToRoot;
this.netIdToNetDesc = netIdToNetDesc;
this.parentInfo = parentInfo;
}
/** The Cell currently being visited. */
public final Cell getCell() {
return cell;
}
/** The Cell that is the root of the traversal */
public final boolean isRootCell() {
return parentInfo == null;
}
/** The VarContext to use for evaluating all variables in the
* current Cell. */
public final VarContext getContext() {
return context;
}
// /** The Netlist of the current Cell. */
// public final Netlist getNetlist() {
// return netlist;
// }
/** Get the CellInfo for the current Cell's parent. If the
* current Cell is the root then return null. */
public final CellInfo getParentInfo() {
return parentInfo;
}
/** Get the NodeInst that instantiates the Current
* instance. If the current Cell is the root then return
* null. */
public final Nodable getParentInst() {
return parentInst;
}
/** Get the CellInfo for the root Cell */
public final CellInfo getRootInfo() {
CellInfo i = this;
while (i.getParentInfo() != null) {
i = i.getParentInfo();
}
return i;
}
/** Get netIDs for the Export: e.
* @return an array of net numbers. */
public final int[] getExportNetIDs(Export e) {
if (isRootCell()) {
// exportNdxToNetIDs is invalid for the root Cell because
// no mapping from net index to netID is performed for Exports
// of the root Cell.
int width = netlist.getBusWidth(e);
int[] netIDs = new int[width];
for (int i = 0; i < width; i++) {
netIDs[i] = netlist.getNetwork(e, i).getNetIndex();
}
return netIDs;
}
return exportNdxToNetIDs[e.getPortIndex() + 1];
}
// /** Map any net inside the current cell to a net
// * number. During the course of the traversal, all nets that
// * map to the same net number are connected. Nets that map to
// * different net numbers are disconnected.
// *
// * If you want to generate a unique name for the net use
// * getUniqueNetName().
// */
// public final int getNetID(Network net) {
// return getNetID(net.getNetIndex());
// }
/**
* Map any arc inside the current cell to a net
* number. During the course of the traversal, all nets that
* map to the same net number are connected. Nets that map to
* different net numbers are disconnected.
*
* If you want to generate a unique name for the net use
* getUniqueNetName().
*/
public final int getNetID(ArcInst ai) {
Network net = netlist.getNetwork(ai, 0);
return net != null ? getNetID(net.getNetIndex()) : -1;
}
/**
* Map any port instance inside the current cell to a net
* number. During the course of the traversal, all nets that
* map to the same net number are connected. Nets that map to
* different net numbers are disconnected.
*
* If you want to generate a unique name for the net use
* getUniqueNetName().
*/
public final int getNetID(NodeInst ni, PortProto p) {
Network net = netlist.getNetwork(parentInst, p, 0);
return net != null ? getNetID(net.getNetIndex()) : -1;
}
/** Map a net index from the current cell to a net ID.
* number. During the course of the traversal, all nets that
* map to the same net number are connected. Nets that map to
* different net numbers are disconnected.
* @param netIndex net index within current cell
* @return net ID that is unique over entire net list.
*/
private int getNetID(int netIndex) {
return netNdxToNetID[netIndex];
}
// public final boolean isGlobalNet(int netID) {
// error(netID<0, "negative netIDs are illegal");
// return netID <= largestGlobalNetID;
// }
/**
* Get the set of netIDs that are connected to the specified port of
* the specified Nodable.
*/
public final int[] getPortNetIDs(Nodable no, PortProto pp) {
return ImmutableLayoutHierarchyEnumerator.getPortNetIDs(no, pp, netlist,
netNdxToNetID);
}
// /** Get a unique, flat net name for the network. The network
// * name will contain the hierarchical context as returned by
// * VarContext.getInstPath() if it is not a top-level network.
// * @param sep the context separator to use if needed.
// * @return a unique String identifier for the network */
// public final String getUniqueNetName(Network net, String sep) {
// NameProxy proxy = getUniqueNetNameProxy(net, sep);
// return proxy.toString();
// }
//
// /** Same as getUniqueNetName except it returns a NameProxy instead of a
// * String name */
// public final NetNameProxy getUniqueNetNameProxy(Network net, String sep) {
// return getUniqueNetNameProxy(getNetID(net), sep);
// }
//
// /** Get a unique, flat net name for the network. The network
// * name will contain the hierarchical context as returned by
// * VarContext.getInstPath() if it is not a top-level network.
// * @param sep the hierarchy separator to use if needed.
// * @return a unique String identifier for the network */
// public final String getUniqueNetName(int netID, String sep) {
// NameProxy proxy = getUniqueNetNameProxy(netID, sep);
// return proxy.toString();
// }
//
// /** Same as getUniqueNetName except it returns a NameProxy instead of a
// * String name */
// public final NetNameProxy getUniqueNetNameProxy(int netID, String sep) {
// NetDescription ns = netIdToNetDesc.get(netID);
// VarContext netContext = ns.getCellInfo().getContext();
// return new NetNameProxy(netContext, sep, ns.getNet());
// }
//
// /** Get a unique, flat instance name for the Nodable.
// * @param no
// * @param sep the hierarchy separator to use if needed
// * @return a unique String identifer for the Nodable */
// public final String getUniqueNodableName(Nodable no, String sep) {
// return getUniqueNodableNameProxy(no, sep).toString();
// }
//
// /** Same as getUniqueNodableName except that it returns a NameProxy
// * instead of a String name. */
// public final NodableNameProxy getUniqueNodableNameProxy(Nodable no, String sep) {
// return new NodableNameProxy(getContext(), sep, no);
// }
//
// /** Get the Network that is closest to the root in the design
// * hierarchy that corresponds to netID. */
// public final NetDescription netIdToNetDescription(int netID) {
// return netIdToNetDesc.get(netID);
// }
//
// /**
// * Get the Network in the parent that connects to the specified
// * Network in this cell. Returns null if no network in parent connects
// * to this network (i.e. network is not connected to export), or null
// * if no parent.
// * @param network the network in this cell
// * @return the network in the parent that connects to the
// * specified network, or null if no such network.
// */
// public Network getNetworkInParent(Network network) {
// if (parentInfo == null) {
// return null;
// }
// if (network == null) {
// return null;
// }
// if (network.getNetlist() != netlist) {
// return null;
// }
// return parentInfo.getNetlist().getNetwork(context.getNodable(), network);
// }
/**
* Method to get the transformation from the current location to the root.
* If this is at the top cell, the transformation is identity.
* @return the transformation from the current location to the root.
*/
public FixpTransform getTransformToRoot() {
return xformToRoot;
}
}
// ----------------------- public methods --------------------------
/** Begin enumeration of the contents of the Cell root. You MUST
* call rebuildNetworks() on the root Cell before calling
* beginEnumeration().
* @param root the starting point of the enumeration.
* @param context the VarContext for evaluating parameters in Cell
* root. If context is null then VarContext.globalContext is used.
* @param visitor the object responsible for doing something useful
* during the enumertion of the design hierarchy. */
public static void enumerateCell(Cell root, VarContext context, Visitor visitor) {
enumerateCell(root, context, visitor, Netlist.ShortResistors.NO);
}
public static void enumerateCell(Cell root, VarContext context, Visitor visitor, Rectangle2D bounds) {
(new ImmutableLayoutHierarchyEnumerator()).doIt(root, context, root.getNetlist(Netlist.ShortResistors.NO), visitor, false, bounds);
}
public static void enumerateCell(Cell root, VarContext context, Visitor visitor, Netlist.ShortResistors shortResistors) {
enumerateCell(root.getNetlist(shortResistors), context, visitor);
}
public static void enumerateCell(Netlist rootNetlist, VarContext context, Visitor visitor) {
enumerateCell(rootNetlist, context, visitor, false);
}
/** Experimental. Optionally caches results of variable evaluation. */
public static void enumerateCell(Netlist rootNetlist, VarContext context, Visitor visitor, boolean caching) {
Netlist.ShortResistors shortResistors = rootNetlist.getShortResistors();
(new ImmutableLayoutHierarchyEnumerator()).doIt(rootNetlist.getCell(), context, rootNetlist, visitor, caching, null);
}
private static class ImmutableNetlist {
private final ImmutableNetLayout impl;
private final int[] nm_net;
private ImmutableNetlist(ImmutableNetLayout impl, Netlist.ShortResistors shortResisors) {
this.impl = impl;
nm_net = new int[impl.netMap.length];
}
private int getNetIndex(ImmutableArcInst a) {
return -1;
}
private int getNetIndex(ImmutableNodeInst n, PortProtoId pp) {
return -1;
}
}
// /**
// * Method to count number of unique cells in hierarchy. Useful
// * for progress tracking of hierarchical netlisters and writers.
// */
// public static int getNumUniqueChildCells(Cell cell) {
// HashMap uniqueChildCells = new HashMap();
// hierCellsRecurse(cell, uniqueChildCells);
// return uniqueChildCells.size();
// }
//
// /** Recursive method used to traverse down hierarchy */
// private static void hierCellsRecurse(Cell cell, HashMap uniqueCells) {
// EDatabase database = cell.getDatabase();
// for (Iterator uit = cell.getUsagesIn(); uit.hasNext();) {
// CellUsage u = uit.next();
// Cell subCell = u.getProto(database);
// if (subCell.isIcon()) {
// continue;
// }
// uniqueCells.put(subCell, subCell);
// hierCellsRecurse(subCell, uniqueCells);
// }
// }
//
// /**
// * Get the Network in the childNodable that corresponds to the Network in the childNodable's
// * parent cell.
// * @param parentNet the network in the parent
// * @param childNodable the child nodable.
// * @return the network in the child that connects to the network in the parent, or
// * null if no such network.
// */
// public static Network getNetworkInChild(Network parentNet, Nodable childNodable) {
// if (childNodable == null || parentNet == null) {
// return null;
// }
// if (!childNodable.isCellInstance()) {
// return null;
// }
// Cell childCell = (Cell) childNodable.getProto();
// Netlist parentNetlist = parentNet.getNetlist();
// Netlist childNetlist = parentNetlist.getNetlist(childNodable);
// PortProto pp = null;
// int i = 0;
// boolean found = false;
// NodeInst ni = childNodable.getNodeInst();
// // find port and index on nodable that is connected to parentNet
// for (Iterator it = ni.getPortInsts(); it.hasNext();) {
// PortInst pi = it.next();
// pp = pi.getPortProto();
// for (i = 0; i < pp.getNameKey().busWidth(); i++) {
// Network net = parentNetlist.getNetwork(childNodable, pp, i);
// if (net == parentNet) {
// found = true;
// break;
// }
// }
// if (found) {
// break;
// }
// }
// if (!found) {
// return null;
// }
// // find corresponding export in child
// if (childCell.contentsView() != null) {
// childCell = childCell.contentsView();
// }
// Export export = childCell.findExport(pp.getNameKey());
// Network childNet = childNetlist.getNetwork(export, i);
// return childNet;
// }
//
// /**
// * Method to search if child network is connected to visitor network (visitorNet).
// * Used in Quick.java and Connection.java.
// */
// public static boolean searchNetworkInParent(Network net, CellInfo info,
// Network visitorNet) {
// if (visitorNet == net) {
// return true;
// }
// CellInfo cinfo = info;
// while (net != null && cinfo.getParentInst() != null) {
// net = cinfo.getNetworkInParent(net);
// if (visitorNet == net) {
// return true;
// }
// cinfo = cinfo.getParentInfo();
// }
// return false;
// }
//
// public static boolean searchInExportNetwork(Network net, CellInfo info,
// Network visitorNet) {
// boolean found = false;
// for (Iterator it = net.getExports(); !found && it.hasNext();) {
// Export exp = it.next();
// Network tmpNet = info.getNetlist().getNetwork(exp, 0);
// found = searchNetworkInParent(tmpNet, info, visitorNet);
// }
// return found;
// }
//
// private static Network getRootNetwork(Network net, CellInfo info) {
// CellInfo cinfo = info;
// Network result = net;
// while (net != null && cinfo.getParentInst() != null) {
// net = cinfo.getNetworkInParent(net);
// if (net != null) {
// result = net;
// }
// cinfo = cinfo.getParentInfo();
// }
// return result;
// }
//
// // Looking for a method to determine if two Geometrics belong to the same network
// public static boolean areGeometricsInSameNetwork(Geometric geo1, Network n1, Geometric geo2, Network n2,
// Cell top) {
// if (n1 == n2) {
// return true; // easy
// }
// // Parent networks at Cell top
// NetworkHierarchy search1 = new NetworkHierarchy(geo1, n1);
// enumerateCell(top, VarContext.globalContext, search1);
// NetworkHierarchy search2 = new NetworkHierarchy(geo2, n2);
// enumerateCell(top, VarContext.globalContext, search2);
// return search1.topNetwork != null && search2.topNetwork != null && search1.topNetwork == search2.topNetwork;
// }
//
// private static class NetworkHierarchy extends ImmutableLayoutHierarchyEnumerator.Visitor {
//
// Geometric theGeo;
// Network childNet;
// Network topNetwork;
//
// NetworkHierarchy(Geometric geo, Network childN) {
// theGeo = geo;
// childNet = childN;
// topNetwork = null;
// }
//
// public boolean enterCell(ImmutableLayoutHierarchyEnumerator.CellInfo info) {
// Cell cell = info.getCell();
//
// // Shall I look for name first? faster?
// // Checking only arcs
// for (Iterator it = cell.getArcs(); it.hasNext();) {
// ArcInst ai = it.next();
// if (ai == theGeo) {
// topNetwork = getRootNetwork(childNet, info);
// return false; // stop looking
// }
// }
// return true; // keep looking?
// }
//
// public void exitCell(ImmutableLayoutHierarchyEnumerator.CellInfo info) {
// }
//
// public boolean visitNodeInst(Nodable no, ImmutableLayoutHierarchyEnumerator.CellInfo info) {
// NodeInst ni = no.getNodeInst();
//
// if (ni.isCellInstance()) {
// return true; // not interested in cells. Keep looking
// }
// if (Generic.isSpecialGenericNode(ni)) {
// return false; // like center or pin. Stop looking
// }
// if (ni == theGeo) // found
// {
// topNetwork = getRootNetwork(childNet, info);
// }
//
// return false; // no need of going down since only PrimitiveNodes reach this point.
// }
// }
}
| | | | |