/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: NetEquivalence.java * * Copyright (c) 2003 Sun Microsystems and Static Free Software * * 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.ncc.result.equivalence; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.Set; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.hierarchy.HierarchyEnumerator; import com.sun.electric.database.hierarchy.Nodable; import com.sun.electric.database.hierarchy.HierarchyEnumerator.CellInfo; import com.sun.electric.database.hierarchy.HierarchyEnumerator.NetNameProxy; import com.sun.electric.database.network.Netlist; import com.sun.electric.database.network.Network; import com.sun.electric.database.network.Netlist.ShortResistors; import com.sun.electric.database.variable.VarContext; import com.sun.electric.tool.generator.layout.NodaNets; import com.sun.electric.tool.generator.layout.NodaNets.NodaPortInst; import com.sun.electric.tool.Job; /** Object to map from a net or node in one design to the * "NCC equivalent" net or node in the * other design. */ class NetEquivalence implements Serializable { static final long serialVersionUID = 0; // ----------------------------- private types ---------------------------- private static class TraceConnectivityUpThroughExports extends HierarchyEnumerator.Visitor { private final String netNm; private final ArrayList<VarContext> netCtxtArray; private int curCtxtNdx; private String nameOfNodableToDescendInto; private boolean doneEnumerating; // this is the result. null if not found private NetNameProxy highestEquivNet; // Build ArrayList of all the VarContext nodes from globalContext to ctxt. // This permits random access. // First element of ArrayList is VarContext.globalContext private static ArrayList<VarContext> buildContextArray(VarContext ctxt) { LinkedList<VarContext> ll = new LinkedList<VarContext>(); Job.error(ctxt==null, "buildContextArray: null ctxt not allowed"); while (true) { ll.addFirst(ctxt); if (ctxt==VarContext.globalContext) break; ctxt = ctxt.pop(); } ArrayList<VarContext> al = new ArrayList<VarContext>(); al.addAll(ll); return al; } private Network findNetworkNamed(Netlist nl, String nm) { for (Iterator<Network> netIt=nl.getNetworks(); netIt.hasNext();) { Network net = netIt.next(); if (net.hasName(nm)) return net; } return null; } private TraceConnectivityUpThroughExports(String netNm, ArrayList<VarContext> netCtxtArray, int curCtxtNdx) { this.netNm = netNm; this.netCtxtArray = netCtxtArray; this.curCtxtNdx = curCtxtNdx; } // ----------------------- overridden methods ------------------------- @Override public boolean visitNodeInst(Nodable no, CellInfo ci) { if (doneEnumerating) return false; if (no.getName().equals(nameOfNodableToDescendInto)) { curCtxtNdx++; return true; } return false; } @Override public boolean enterCell(CellInfo ci) { if (doneEnumerating) return false; if (curCtxtNdx==netCtxtArray.size()-1) { // We've descended into the Cell containing the sought Network // Now find the Network. doneEnumerating = true; Netlist nl = ci.getNetlist(); Network net = findNetworkNamed(nl, netNm); if (net==null) return false; // no net matching name! highestEquivNet = ci.getUniqueNetNameProxy(net, "/"); return false; } else { // We need to descend once more nameOfNodableToDescendInto = netCtxtArray.get(curCtxtNdx+1).getNodable().getName(); return true; } } @Override public void exitCell(CellInfo ci) {} // --------------------- intended interface --------------------------- /** Trace the connectivity through Exports to find the Network * in the highest Cell in the design hierarchy that is connected to * Network net. <p> * Subtle: Begin the enumeration from the point at which NCC began the * enumeration because VarContext above that point isn't guaranteed to make * sense (e.g. VarContext might point to deleted instance) */ public static NetNameProxy findHighestNet(Network net, VarContext netCtxt, Cell nccRootCell, VarContext nccRootCtxt) { ArrayList<VarContext> nccRootCtxtArray = buildContextArray(nccRootCtxt); ArrayList<VarContext> netCtxtArray = buildContextArray(netCtxt); int nccRootDepth = nccRootCtxtArray.size(); // make sure the initial portion of the netCtxt matches the // nccRootCtxt if (netCtxtArray.size()<nccRootDepth || !netCtxtArray.get(nccRootDepth-1).equals(nccRootCtxt)) { return null; } TraceConnectivityUpThroughExports visitor = new TraceConnectivityUpThroughExports(net.getName(), netCtxtArray, nccRootDepth-1); HierarchyEnumerator.enumerateCell(nccRootCell, nccRootCtxt, visitor); return visitor.highestEquivNet; } } // --------------------------- private data ------------------------------- private final NetNameProxy[][] equivNets; private final Cell[] nccRootCells; private final VarContext[] nccRootCtxts; private final int numDesigns, numNets; private InstancePathToNccContext[] instToNetNccCtxt; /** Cache the index of the last design that satisified the last * findEquivalent() query? */ private int lastDesignHit; private boolean nameMatch(NetNameProxy prox, Network net) { for (Iterator<String> it=prox.leafNames(); it.hasNext();) { String proxNm = it.next(); if (net.hasName(proxNm)) return true; } return false; } private void pr(String s) {System.out.print(s);} private void prln(String s) {System.out.println(s);} /** Tricky: Because instToNetNcCtxt takes so much space, build it * only on demand */ private void buildNameTree() { if (instToNetNccCtxt!=null) return; instToNetNccCtxt = new InstancePathToNccContext[numDesigns]; for (int i=0; i<numDesigns; i++) { Job.error(equivNets[i].length!=numNets, "designs don't have same numbers of nets?"); instToNetNccCtxt[i] = new InstancePathToNccContext(equivNets[i]); } } /** @param equivNets is a NetNameProxy[][]. NetNameProxy[d][n] gives the * nth net of the dth design. NetNameProxy[a][n] is "NCC equivalent" to * NetNameProxy[b][n] for all a and b.*/ public NetEquivalence(NetNameProxy[][] equivNets, Cell[] nccRootCells, VarContext[] nccRootCtxts) { this.equivNets = equivNets; numDesigns = equivNets.length; numNets = equivNets[0].length; this.nccRootCells = nccRootCells; this.nccRootCtxts = nccRootCtxts; } private NetNameProxy findEquivNet(VarContext vc, Network net, int designIndex) { Job.error(designIndex!=0 && designIndex!=1, "designIndex must be 0 or 1"); buildNameTree(); InstancePathToNccContext nameIndex = instToNetNccCtxt[designIndex]; NccContext nc = nameIndex.findNccContext(vc); if (nc==null) return null; if (nc.getCell()!=net.getParent()) return null; if (!nc.getContext().equals(vc)) return null; for (Iterator<Integer> it=nc.getIndices(); it.hasNext();) { int index = it.next().intValue(); NetNameProxy prox = equivNets[designIndex][index]; if (nameMatch(prox, net)) { int equivDesign = designIndex==0 ? 1 : 0; return equivNets[equivDesign][index]; } } return null; } private int countUnique() { Set<Network> networks = new HashSet<Network>(); for (int i=0; i<2; i++) { for (int j=0; j<numNets; j++) networks.add(equivNets[i][j].getNet()); } return networks.size(); } private NodaPortInst getPortFromUnshortedNet(Network n) { NodaNets noshortNets = new NodaNets(n.getParent(), ShortResistors.NO); Collection<NodaPortInst> ports = noshortNets.getPorts(n); for (NodaPortInst pi : ports) return pi; Job.error(true, "No ports found on Network?"); return null; } // GUI netlists don't treat resistors as shorts. Let's find an // equivalent shorted-resistor Network. This is tricky. All // Networks except globals are guaranteed to be connected to at // least one port. Therefore find a port on the old network, // short resistors, and try to find the network connected to the // same port. private Network netWhenResShorted(Network n) { // if resistors already shorted then nothing else can be done if (n.getNetlist().getShortResistors() == Netlist.ShortResistors.PARASITIC) return null; prln(" RK Debug: Try shorting resistors"); NodaPortInst port = getPortFromUnshortedNet(n); NodaNets shortedNets = new NodaNets(n.getParent(), ShortResistors.PARASITIC); Nodable no = shortedNets.getNoda(port.getNodable().getName()); for (NodaPortInst pi : shortedNets.getPorts(no)) { if (pi.getIndex()==port.getIndex() && pi.getPortProto()==port.getPortProto()) { return pi.getNet(); } } prln(" RK Debug: Shorting resistors fails"); return null; } /** Given a Network located at point in the design hierarchy specified by a * VarContext, find the "NCC equivalent" net in the other design. * <p> * Subtle: Because the user interface may rebuild the Networks, we cannot * depend upon Network "==" for equality. Instead I depend upon 1) the * .equals() equality of instance names along the VarContext, 2) the .equals() * equality of the VarContext (which depends upon the == equality of Nodables * along the VarContext), 3) the .equals equality of the names of the Network. * 4) the == equality of the parent Cells of the Network * @param vc VarContext specifying a point in the hierarchy. * @param net Network located at that point in the hierarchy. * @return the "NCC equivalent" NetNameProxy or null if no equivalent can * be found. */ public NetNameProxy findEquivalentNet(VarContext vc, Network net) { NetNameProxy nnp = findEquivNet(vc, net, lastDesignHit); if (nnp!=null) return nnp; int otherDesign = lastDesignHit==0 ? 1 : 0; nnp = findEquivNet(vc, net, otherDesign); if (nnp!=null) {lastDesignHit=otherDesign; return nnp;} // net may be connected to an Export. If so, find the Network highest // in the design hierarchy connected to net if (!net.isExported()) return null; NetNameProxy higherNet = TraceConnectivityUpThroughExports.findHighestNet(net, vc, nccRootCells[lastDesignHit], nccRootCtxts[lastDesignHit]); if (higherNet!=null) { nnp = findEquivNet(higherNet.getContext(), higherNet.getNet(), lastDesignHit); if (nnp!=null) {return nnp;} } higherNet = TraceConnectivityUpThroughExports.findHighestNet(net, vc, nccRootCells[otherDesign], nccRootCtxts[otherDesign]); if (higherNet!=null) { nnp = findEquivNet(higherNet.getContext(), higherNet.getNet(), lastDesignHit); if (nnp!=null) {lastDesignHit=otherDesign; return nnp;} } return null; } public NetNameProxy findEquivalentNetShortingResistors(VarContext vc, Network net) { NetNameProxy eqProx = findEquivalentNet(vc, net); if (eqProx==null) { // try extending this net by shorting resistors net = netWhenResShorted(net); if (net==null) return null; eqProx = findEquivalentNet(vc, net); if (eqProx==null) return null; } return eqProx; } /** Release cached information when you no longer need the Equivalence * information. */ void clearCache() { instToNetNccCtxt = null; } /** Regression test. Map from every net in design 0 to "NCC equivalent" * net in design 1. Map from every net in design 1 to "NCC equivalent" * net in design 0. * @return the number of errors. */ public int regressionTest() { Job.error(numDesigns!=2, "we must have exactly two designs"); int numErrors = 0; for (int desNdx=0; desNdx<numDesigns; desNdx++) { int otherDesign = desNdx==0 ? 1 : 0; for (int netNdx=0; netNdx<numNets; netNdx++) { NetNameProxy from = equivNets[desNdx][netNdx]; VarContext fromVc = from.getContext(); Network fromNet = from.getNet(); NetNameProxy to = findEquivalentNet(fromVc, fromNet); if (to!=equivNets[otherDesign][netNdx]) { numErrors++; // Print Diagnostics prln(" From: "+from.toString()); prln(" To: "+(to==null?"null":to.toString())); prln(" Equiv: "+equivNets[otherDesign][netNdx]); } } } pr(" Net equivalence regression "+ (numErrors==0 ? "passed. " : "failed. ")); pr(" Equiv table size="+numNets+". "); pr(" Num unique Networks="+countUnique()+". "); if (numErrors!=0) System.out.print(numErrors+" errors."); pr("\n"); return numErrors; } }