/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: NetSchem.java * Written by: Dmitry Nadezhin, Sun Microsystems. * * 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.network; import com.sun.electric.database.CellTree; import com.sun.electric.database.EquivPorts; import com.sun.electric.database.EquivalentSchematicExports; import com.sun.electric.database.Snapshot; 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.CellId; import com.sun.electric.database.prototype.NodeProto; import com.sun.electric.database.prototype.PortCharacteristic; import com.sun.electric.database.prototype.PortProto; import com.sun.electric.database.text.Name; import com.sun.electric.database.topology.ArcInst; import com.sun.electric.database.topology.Connection; import com.sun.electric.database.topology.IconNodeInst; import com.sun.electric.database.topology.NodeInst; import com.sun.electric.database.topology.PortInst; import com.sun.electric.technology.ArcProto; import com.sun.electric.technology.PrimitiveNode; import com.sun.electric.technology.technologies.Schematics; import com.sun.electric.util.math.GenMath; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; /** * This is the mirror of group of Icon and Schematic cells in Network tool. */ class NetSchem extends NetCell { /** Check immutable algorithm which computes equivalent ports */ private static final boolean CHECK_EQUIV_PORTS = true; private class IconInst { final NodeInst nodeInst; final boolean iconOfParent; final Nodable[] iconNodables; final int netMapOffset; final int numExtendedExports; final EquivalentSchematicExports eq; private IconInst(NodeInst nodeInst, int nodeOffset) { Cell proto = (Cell) nodeInst.getProto(); assert proto.isIcon() || proto.isSchematic(); this.nodeInst = nodeInst; iconOfParent = nodeInst.isIconOfParent(); iconNodables = iconOfParent ? null : new Nodable[nodeInst.getNameKey().busWidth()]; this.netMapOffset = nodeOffset; eq = iconOfParent ? null : nodeInst.getDatabase().backup().getEquivExports(proto.getId()); this.numExtendedExports = iconOfParent ? -1000000 : eq.implementation.numExpandedExports; } private int getNetMapOffset(Nodable proxy) { int arrayIndex = proxy.getNodableArrayIndex(); assert iconNodables[arrayIndex] == proxy; return netMapOffset + arrayIndex * numExtendedExports; } } /* Implementation of this NetSchem. */ NetSchem implementation; /** Node offsets. */ int[] drawnOffsets; /** Info for instances of Icons */ IconInst[] iconInsts; /** IconInsts with global rebindes. */ IdentityHashMap<IconInst, Set<Global>> iconInstExcludeGlobals; /** */ Global.Set globals = Global.Set.empty; /** */ int[] portOffsets = new int[1]; /** */ int netNamesOffset; /** */ Name[] drawnNames; /** */ int[] drawnWidths; private IdentityHashMap<Name, Integer> exportNameMapOffsets; private CellTree cellTree; private CellId mainSchemId; private IdentityHashMap<CellId, EquivalentSchematicExports> eqExports; NetSchem(Cell cell) { super(cell); setImplementation(this); if (cell.isIcon()) { Cell mainSchematics = cell.getCellGroup().getMainSchematics(); if (mainSchematics != null) { NetSchem mainSchem = new NetSchem(mainSchematics); setImplementation(mainSchem); } } } // NetSchem(Cell.CellGroup cellGroup) { // super(cellGroup.getMainSchematics()); // } private void setImplementation(NetSchem implementation) { if (this.implementation == implementation) { return; } this.implementation = implementation; // updatePortImplementation(); } // private boolean updatePortImplementation() { // boolean changed = false; // int numPorts = cell.getNumPorts(); // if (portImplementation == null || portImplementation.length != numPorts) { // changed = true; // portImplementation = new int[numPorts]; // } // Cell c = implementation.cell; // for (int i = 0; i < numPorts; i++) { // Export e = cell.getPort(i); // int equivIndex = -1; // if (c != null) { // Export equiv = e.getEquivalentPort(c); // if (equiv != null) { // equivIndex = equiv.getPortIndex(); // } // } // if (portImplementation[i] != equivIndex) { // changed = true; // portImplementation[i] = equivIndex; // } // if (equivIndex < 0) { // String msg = cell + ": Icon port <" + e.getNameKey() + "> has no equivalent port"; // System.out.println(msg); // networkManager.pushHighlight(e); // networkManager.logError(msg, NetworkTool.errorSortPorts); // } // } // if (c != null && numPorts != c.getNumPorts()) { // for (int i = 0; i < c.getNumPorts(); i++) { // Export e = c.getPort(i); // if (e.getEquivalentPort(cell) == null) { // String msg = c + ": Schematic port <" + e.getNameKey() + "> has no equivalent port in " + cell; // System.out.println(msg); // networkManager.pushHighlight(e); // networkManager.logError(msg, NetworkTool.errorSortPorts); // } // } // } // return changed; // } // @Override // int getPortOffset(int portIndex, int busIndex) { // portIndex = portImplementation[portIndex]; // if (portIndex < 0) { // return -1; // } // int portOffset = implementation.portOffsets[portIndex] + busIndex; // if (busIndex < 0 || portOffset >= implementation.portOffsets[portIndex + 1]) { // return -1; // } // return portOffset; // } @Override NetSchem getSchem() { return implementation; } /** * Get an iterator over all of the Nodables of this Cell. */ @Override Iterator<Nodable> getNodables() { ArrayList<Nodable> nodables = new ArrayList<Nodable>(); for (Iterator<NodeInst> it = cell.getNodes(); it.hasNext();) { NodeInst ni = it.next(); if (iconInsts[ni.getNodeIndex()] != null) { continue; } nodables.add(ni); } for (IconInst iconInst : iconInsts) { if (iconInst == null || iconInst.iconOfParent) { continue; } for (int i = 0; i < iconInst.iconNodables.length; i++) { Nodable proxy = iconInst.iconNodables[i]; assert proxy != null; nodables.add(proxy); } } return nodables.iterator(); } /** * Get a set of global signal in this Cell and its descendants. */ @Override Global.Set getGlobals() { return globals; } /* * Get offset in networks map for given global signal. */ @Override int getNetMapOffset(Global global) { return globals.indexOf(global); } /** * Get offset in networks map for given global of nodable. * @param no nodable. * @param global global signal. * @return offset in networks map. */ @Override int getNetMapOffset(Nodable no, Global global) { if (no == null) { return -1; } int nodeIndex = no.getNodeInst().getNodeIndex(); if (nodeIndex < 0 || nodeIndex >= iconInsts.length) { return -1; } IconInst iconInst = iconInsts[nodeIndex]; if (iconInst == null || iconInst.iconOfParent) { return -1; } assert !(no instanceof NodeInst) || no == iconInst.nodeInst && ((Cell) iconInst.nodeInst.getProto()).isSchematic(); int indexOfGlobal = iconInst.eq.implementation.globals.indexOf(global); if (indexOfGlobal < 0) { return -1; } return iconInst.getNetMapOffset(no) + indexOfGlobal; } /** * Get offset in networks map for given subnetwork of nodable. * @param no nodable. * @param equivPortIndex index of entry in equivPortsX * @return offset in networks map. */ @Override int getNetMapOffset(Nodable no, int equivPortIndex) { int nodeIndex = no.getNodeInst().getNodeIndex(); if (nodeIndex < 0 || nodeIndex >= iconInsts.length) { return -1; } IconInst iconInst = iconInsts[nodeIndex]; if (iconInst == null || iconInst.iconOfParent) { return -1; } return iconInst.getNetMapOffset(no) + equivPortIndex; } /* * Get offset in networks map for given port instance. */ @Override int getNetMapOffset(Nodable no, PortProto portProto, int busIndex) { if (no == null) { return -1; } int nodeIndex = no.getNodeInst().getNodeIndex(); if (nodeIndex < 0 || nodeIndex >= iconInsts.length) { return -1; } IconInst iconInst = iconInsts[nodeIndex]; if (iconInst == null) { // primitive or layout cell int drawn = drawns[ni_pi[nodeIndex] + portProto.getPortIndex()]; if (drawn < 0) { return -1; } if (busIndex < 0 || busIndex >= drawnWidths[drawn]) { return -1; } assert portProto.getParent() == ((NodeInst) no).getProto(); return drawnOffsets[drawn] + busIndex; } else if (iconInst.iconOfParent) { return -1; } else { // icon or schematic cell Cell subCell = (Cell) portProto.getParent(); assert no.getProto() == subCell; EquivalentSchematicExports eq = iconInst.eq; if (no instanceof IconNodeInst) { Nodable no1 = ((IconNodeInst) no).getNodable(0); // if (Job.getDebug()) { // System.out.println("IconNodeInst " + no + " is passed to getNodeIndex. Replaced by IconNodeable " + no1); // } assert eq.cellId == subCell.getId(); no = no1; } else { assert eq.implementation.cellId == subCell.getId(); } Name exportName = portProto.getNameKey().subname(busIndex); int portOffset = eq.implementation.getExportNameMapOffset(exportName); if (portOffset < 0) { return -1; } return iconInst.getNetMapOffset(no) + portOffset; } } /* * Get offset in networks map for given port instance. */ @Override int getNetMapOffset(Nodable no, Name portName) { if (no == null) { return -1; } int nodeIndex = no.getNodeInst().getNodeIndex(); if (nodeIndex < 0 || nodeIndex >= iconInsts.length) { return -1; } IconInst iconInst = iconInsts[nodeIndex]; if (iconInst == null) { // primitive or layout cell PortProto portProto = no.getParent().findPortProto(portName); int drawn = drawns[ni_pi[nodeIndex] + portProto.getPortIndex()]; if (drawn < 0) { return -1; } if (drawnWidths[drawn] != 1) { throw new IllegalArgumentException(); } assert portProto.getParent() == ((NodeInst) no).getProto(); return drawnOffsets[drawn]; } else if (iconInst.iconOfParent) { return -1; } else { // icon or schematic cell Cell subCell = (Cell) no.getProto(); EquivalentSchematicExports eq = iconInst.eq; if (no instanceof IconNodeInst) { Nodable no1 = ((IconNodeInst) no).getNodable(0); // if (Job.getDebug()) { // System.out.println("IconNodeInst " + no + " is passed to getNodeIndex. Replaced by IconNodeable " + no1); // } assert eq.cellId == subCell.getId(); no = no1; } else { assert eq.implementation.cellId == subCell.getId(); } int portOffset = eq.implementation.getExportNameMapOffset(portName); if (portOffset < 0) { return -1; } return iconInst.getNetMapOffset(no) + portOffset; } } /** * Method to return the port width of port of the Nodable. * @return the either the port width. */ @Override int getBusWidth(Nodable no, PortProto portProto) { if (no instanceof NodeInst) { NodeInst ni = (NodeInst) no; int nodeIndex = ni.getNodeIndex(); // int proxyOffset = nodeOffsets[nodeIndex]; //if (proxyOffset >= 0) { int drawn = drawns[ni_pi[nodeIndex] + portProto.getPortIndex()]; if (drawn < 0) { return 0; } return drawnWidths[drawn]; //} } else { return portProto.getNameKey().busWidth(); } } /* * Get offset in networks map for given export. */ @Override int getNetMapOffset(Export export, int busIndex) { int drawn = drawns[export.getPortIndex()]; if (drawn < 0) { return -1; } if (busIndex < 0 || busIndex >= drawnWidths[drawn]) { return -1; } return drawnOffsets[drawn] + busIndex; } /* * Get offset in networks map for given export name. */ @Override int getNetMapOffset(Name exportName) { assert !exportName.isBus(); if (exportNameMapOffsets == null) { buildExportNameMapOffsets(); } Integer objResult = exportNameMapOffsets.get(exportName); return objResult != null ? objResult.intValue() : -1; } private void buildExportNameMapOffsets() { IdentityHashMap<Name, Integer> map = new IdentityHashMap<Name, Integer>(); for (int exportIndex = 0; exportIndex < cell.getNumPorts(); exportIndex++) { Export e = cell.getPort(exportIndex); for (int busIndex = 0; busIndex < e.getNameKey().busWidth(); busIndex++) { Name exportName = e.getNameKey().subname(busIndex); if (map.containsKey(exportName)) { continue; } map.put(exportName, Integer.valueOf(portOffsets[exportIndex] + busIndex)); } } exportNameMapOffsets = map; } /* * Get offset in networks map for given arc. */ @Override int getNetMapOffset(ArcInst ai, int busIndex) { int drawn = getArcDrawn(ai); if (drawn < 0) { return -1; } if (busIndex < 0 || busIndex >= drawnWidths[drawn]) { return -1; } return drawnOffsets[drawn] + busIndex; } /** * Method to return either the network name or the bus name on this ArcInst. * @return the either the network name or the bus n1ame on this ArcInst. */ @Override Name getBusName(ArcInst ai) { int drawn = getArcDrawn(ai); return drawnNames[drawn]; } /** * Method to return the bus width on this ArcInst. * @return the either the bus width on this ArcInst. */ @Override public int getBusWidth(ArcInst ai) { // if ((flags & VALID) == 0) { // redoNetworks(); // } int drawn = getArcDrawn(ai); if (drawn < 0) { return 0; } return drawnWidths[drawn]; } private boolean initNodables() { int numNodes = cell.getNumNodes(); Global.Buf globalBuf = new Global.Buf(); Map<NodeInst, Set<Global>> nodeInstExcludeGlobal = null; for (int i = 0; i < numNodes; i++) { NodeInst ni = cell.getNode(i); NodeProto np = ni.getProto(); if (ni.isCellInstance()) { Cell subCell = (Cell) np; if (!(subCell.isIcon() || subCell.isSchematic())) { if (ni.getNameKey().isBus()) { String msg = cell + ": Array name <" + ni.getNameKey() + "> can be assigned only to icon nodes"; System.out.println(msg); networkManager.pushHighlight(ni); networkManager.logError(msg, NetworkTool.errorSortNodes); } continue; } if (ni.getNameKey().hasDuplicates()) { String msg = cell + ": Node name <" + ni.getNameKey() + "> has duplicate subnames"; System.out.println(msg); networkManager.pushHighlight(ni); networkManager.logError(msg, NetworkTool.errorSortNodes); } if (ni.isIconOfParent()) { continue; } EquivalentSchematicExports eq = database.backup().getEquivExports(subCell.getId()); Global.Set gs = eq.implementation.globals; // Check for rebinding globals if (eq.implementation.globalPartitions != null) { int numPortInsts = np.getNumPorts(); Set<Global> gb = null; for (int j = 0; j < numPortInsts; j++) { PortInst pi = ni.getPortInst(j); int piOffset = getPortInstOffset(pi); int drawn = drawns[piOffset]; if (drawn < 0 || drawn >= numConnectedDrawns) { continue; } Export e = (Export) pi.getPortProto(); Name busName = e.getNameKey(); for (int busIndex = 0; busIndex < busName.busWidth(); busIndex++) { Name exportName = busName.subname(busIndex); Global.Set globalsOnElement = eq.implementation.globalPartitions.get(exportName); if (globalsOnElement == null) { continue; } if (gb == null) { gb = new HashSet<Global>(); } for (int l = 0; l < globalsOnElement.size(); l++) { Global g = globalsOnElement.get(l); gb.add(g); } } } if (gb != null) { // remember excluded globals for this NodeInst if (nodeInstExcludeGlobal == null) { nodeInstExcludeGlobal = new HashMap<NodeInst, Set<Global>>(); } nodeInstExcludeGlobal.put(ni, gb); // fix Set of globals gs = gs.remove(gb.iterator()); } } String errorMsg = globalBuf.addToBuf(gs); if (errorMsg != null) { String msg = "Network: " + cell + " has globals with conflicting characteristic " + errorMsg; System.out.println(msg); networkManager.logError(msg, NetworkTool.errorSortNetworks); // TODO: what to highlight? // log.addGeom(shared[i].nodeInst, true, 0, null); } } else { Global g = globalInst(ni); if (g != null) { PortCharacteristic characteristic; if (g == Global.ground) { characteristic = PortCharacteristic.GND; } else if (g == Global.power) { characteristic = PortCharacteristic.PWR; } else { characteristic = PortCharacteristic.findCharacteristic(ni.getTechSpecific()); if (characteristic == null) { String msg = "Network: " + cell + " has global " + g.getName() + " with unknown characteristic bits"; System.out.println(msg); networkManager.pushHighlight(ni); networkManager.logError(msg, NetworkTool.errorSortNetworks); characteristic = PortCharacteristic.UNKNOWN; } } String errorMsg = globalBuf.addToBuf(g, characteristic); if (errorMsg != null) { String msg = "Network: " + cell + " has global with conflicting characteristic " + errorMsg; System.out.println(msg); networkManager.logError(msg, NetworkTool.errorSortNetworks); //log.addGeom(shared[i].nodeInst, true, 0, null); } } } } Global.Set newGlobals = globalBuf.getBuf(); boolean changed = false; if (globals != newGlobals) { changed = true; globals = newGlobals; if (NetworkTool.debug) { System.out.println(cell + " has " + globals); } } int mapOffset = portOffsets[0] = globals.size(); int numPorts = cell.getNumPorts(); for (int i = 1; i <= numPorts; i++) { Export export = cell.getPort(i - 1); if (NetworkTool.debug) { System.out.println(export + " " + portOffsets[i - 1]); } mapOffset += export.getNameKey().busWidth(); if (portOffsets[i] != mapOffset) { changed = true; portOffsets[i] = mapOffset; } } if (equivPortsN == null || equivPortsN.length != mapOffset) { equivPortsN = new int[mapOffset]; equivPortsP = new int[mapOffset]; equivPortsA = new int[mapOffset]; } for (int i = 0; i < numDrawns; i++) { drawnOffsets[i] = mapOffset; mapOffset += drawnWidths[i]; if (NetworkTool.debug) { System.out.println("Drawn " + i + " has offset " + drawnOffsets[i]); } } iconInsts = new IconInst[cell.getNumNodes()]; iconInstExcludeGlobals = null; for (int n = 0; n < numNodes; n++) { NodeInst ni = cell.getNode(n); if (!ni.isCellInstance()) { continue; } Cell iconCell = (Cell) ni.getProto(); if (!(iconCell.isIcon() || iconCell.isSchematic())) { continue; } IconInst iconInst = new IconInst(ni, mapOffset); iconInsts[n] = iconInst; if (ni.isIconOfParent()) { assert iconInst.iconOfParent && iconInst.iconNodables == null; continue; } Set<Global> gs = nodeInstExcludeGlobal != null ? nodeInstExcludeGlobal.get(ni) : null; // exclude set of globals if (gs != null) { if (iconInstExcludeGlobals == null) { iconInstExcludeGlobals = new IdentityHashMap<IconInst, Set<Global>>(); } iconInstExcludeGlobals.put(iconInst, gs); } for (int i = 0; i < ni.getNameKey().busWidth(); i++) { Nodable proxy; if (ni instanceof IconNodeInst) { proxy = ((IconNodeInst) ni).getNodable(i); } else { assert ni.getNameKey().busWidth() == 1; proxy = ni; } iconInst.iconNodables[i] = proxy; assert iconInst.getNetMapOffset(proxy) == mapOffset; mapOffset += iconInst.numExtendedExports; } } netNamesOffset = mapOffset; if (NetworkTool.debug) { System.out.println("netNamesOffset=" + netNamesOffset); } return changed; } private static Global globalInst(NodeInst ni) { NodeProto np = ni.getProto(); if (np == Schematics.tech().groundNode) { return Global.ground; } if (np == Schematics.tech().powerNode) { return Global.power; } if (np == Schematics.tech().globalNode) { String globalName = ni.getVarValue(Schematics.SCHEM_GLOBAL_NAME, String.class); if (globalName != null) { return Global.newGlobal(globalName); } } return null; } void calcDrawnWidths() { Arrays.fill(drawnNames, null); Arrays.fill(drawnWidths, -1); int numPorts = cell.getNumPorts(); int numNodes = cell.getNumNodes(); int numArcs = cell.getNumArcs(); for (int i = 0; i < numPorts; i++) { int drawn = drawns[i]; Name name = cell.getPort(i).getNameKey(); int newWidth = name.busWidth(); int oldWidth = drawnWidths[drawn]; if (oldWidth < 0) { drawnNames[drawn] = name; drawnWidths[drawn] = newWidth; continue; } if (oldWidth != newWidth) { reportDrawnWidthError(cell.getPort(i), null, drawnNames[drawn].toString(), name.toString()); if (oldWidth < newWidth) { drawnNames[drawn] = name; drawnWidths[drawn] = newWidth; } } } int arcIndex = 0; for (Iterator<ArcInst> it = cell.getArcs(); arcIndex < numArcs; arcIndex++) { ArcInst ai = it.next(); int drawn = drawns[arcsOffset + arcIndex]; if (drawn < 0) { continue; } Name name = ai.getNameKey(); if (name.isTempname()) { continue; } int newWidth = name.busWidth(); int oldWidth = drawnWidths[drawn]; if (oldWidth < 0) { drawnNames[drawn] = name; drawnWidths[drawn] = newWidth; continue; } if (oldWidth != newWidth) { reportDrawnWidthError(null, ai, drawnNames[drawn].toString(), name.toString()); if (oldWidth < newWidth) { drawnNames[drawn] = name; drawnWidths[drawn] = newWidth; } } } ArcProto busArc = Schematics.tech().bus_arc; arcIndex = 0; for (Iterator<ArcInst> it = cell.getArcs(); arcIndex < numArcs; arcIndex++) { ArcInst ai = it.next(); int drawn = drawns[arcsOffset + arcIndex]; if (drawn < 0) { continue; } Name name = ai.getNameKey(); if (!name.isTempname()) { continue; } int oldWidth = drawnWidths[drawn]; if (oldWidth < 0) { drawnNames[drawn] = name; if (ai.getProto() != busArc) { drawnWidths[drawn] = 1; } } } for (int i = 0; i < numNodes; i++) { NodeInst ni = cell.getNode(i); NodeProto np = ni.getProto(); if (!ni.isCellInstance()) { if (np.getFunction().isPin()) { continue; } if (np == Schematics.tech().offpageNode) { continue; } } int numPortInsts = np.getNumPorts(); for (int j = 0; j < numPortInsts; j++) { PortInst pi = ni.getPortInst(j); int drawn = drawns[getPortInstOffset(pi)]; if (drawn < 0) { continue; } int oldWidth = drawnWidths[drawn]; int newWidth = 1; if (ni.isCellInstance()) { Cell subCell = (Cell) np; if (subCell.isIcon() || subCell.isSchematic()) { int arraySize = subCell.isIcon() ? ni.getNameKey().busWidth() : 1; int portWidth = pi.getPortProto().getNameKey().busWidth(); if (oldWidth == portWidth) { continue; } newWidth = arraySize * portWidth; } } if (oldWidth < 0) { drawnWidths[drawn] = newWidth; continue; } if (oldWidth != newWidth) { String msg = "Network: Schematic " + cell + " has net <" + drawnNames[drawn] + "> with width conflict in connection " + pi.describe(true); System.out.println(msg); networkManager.pushHighlight(pi); networkManager.logError(msg, NetworkTool.errorSortNetworks); } } } for (int i = 0; i < drawnWidths.length; i++) { if (drawnWidths[i] < 1) { drawnWidths[i] = 1; } if (NetworkTool.debug) { System.out.println("Drawn " + i + " " + (drawnNames[i] != null ? drawnNames[i].toString() : "") + " has width " + drawnWidths[i]); } } } // this method will not be called often because user will fix error, so it's not // very efficient. void reportDrawnWidthError(Export pp, ArcInst ai, String firstname, String badname) { // first occurrence is initial width which all subsequents are compared to int numPorts = cell.getNumPorts(); int numArcs = cell.getNumArcs(); String msg = "Network: Schematic " + cell + " has net with conflict width of names <" + firstname + "> and <" + badname + ">"; System.out.println(msg); boolean originalFound = false; for (int i = 0; i < numPorts; i++) { String name = cell.getPort(i).getName(); if (name.equals(firstname)) { networkManager.pushHighlight(cell.getPort(i)); originalFound = true; break; } } if (!originalFound) { for (Iterator<ArcInst> it = cell.getArcs(); it.hasNext();) { ArcInst oai = it.next(); String name = oai.getName(); if (name.equals(firstname)) { networkManager.pushHighlight(oai); break; } } } if (ai != null) { networkManager.pushHighlight(ai); } if (pp != null) { networkManager.pushHighlight(pp); } networkManager.logError(msg, NetworkTool.errorSortNetworks); } @Override void addNetNames(Name name, Export e, ArcInst ai) { for (int i = 0; i < name.busWidth(); i++) { addNetName(name.subname(i), e, ai); } } private void localConnections(int netMap[]) { // Exports int numExports = cell.getNumPorts(); for (int k = 0; k < numExports; k++) { Export e = cell.getPort(k); int portOffset = portOffsets[k]; Name expNm = e.getNameKey(); int busWidth = expNm.busWidth(); int drawn = drawns[k]; int drawnOffset = drawnOffsets[drawn]; for (int i = 0; i < busWidth; i++) { Netlist.connectMap(netMap, portOffset + i, drawnOffset + (busWidth == drawnWidths[drawn] ? i : i % drawnWidths[drawn])); GenMath.MutableInteger nn = netNames.get(expNm.subname(i)); Netlist.connectMap(netMap, portOffset + i, netNamesOffset + nn.intValue()); } } // PortInsts int numNodes = cell.getNumNodes(); for (int k = 0; k < numNodes; k++) { NodeInst ni = cell.getNode(k); NodeProto np = ni.getProto(); if (!ni.isCellInstance()) { // Connect global primitives Global g = globalInst(ni); if (g != null) { int drawn = drawns[ni_pi[k]]; Netlist.connectMap(netMap, globals.indexOf(g), drawnOffsets[drawn]); } if (np == Schematics.tech().wireConNode) { connectWireCon(netMap, ni); } continue; } IconInst iconInst = iconInsts[k]; if (iconInst == null || iconInst.iconOfParent) { continue; } Cell subCell = (Cell) np; assert subCell.isIcon() || subCell.isSchematic(); EquivalentSchematicExports eq = iconInst.eq; Name nodeName = ni.getNameKey(); int arraySize = nodeName.busWidth(); int numPorts = np.getNumPorts(); for (int m = 0; m < numPorts; m++) { Export e = (Export) np.getPort(m); Name busExportName = e.getNameKey(); int busWidth = busExportName.busWidth(); int drawn = drawns[ni_pi[k] + m]; if (drawn < 0) { continue; } int width = drawnWidths[drawn]; if (width != busWidth && width != busWidth * arraySize) { continue; } assert arraySize == iconInst.iconNodables.length; for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { int nodeOffset = iconInst.netMapOffset + arrayIndex * iconInst.numExtendedExports; int busOffset = drawnOffsets[drawn]; if (width != busWidth) { busOffset += busWidth * arrayIndex; } for (int j = 0; j < busWidth; j++) { Name exportName = busExportName.subname(j); int portOffset = eq.implementation.getExportNameMapOffset(exportName); if (portOffset < 0) { continue; } Netlist.connectMap(netMap, busOffset + j, nodeOffset + portOffset); } } } } // Arcs int numArcs = cell.getNumArcs(), arcIndex = 0; for (Iterator<ArcInst> it = cell.getArcs(); arcIndex < numArcs; arcIndex++) { ArcInst ai = it.next(); int drawn = drawns[arcsOffset + arcIndex]; if (drawn < 0) { continue; } if (!ai.isUsernamed()) { continue; } int busWidth = drawnWidths[drawn]; Name arcNm = ai.getNameKey(); if (arcNm.busWidth() != busWidth) { continue; } int drawnOffset = drawnOffsets[drawn]; for (int i = 0; i < busWidth; i++) { GenMath.MutableInteger nn = netNames.get(arcNm.subname(i)); Netlist.connectMap(netMap, drawnOffset + i, netNamesOffset + nn.intValue()); } } // Globals of proxies for (IconInst iconInst : iconInsts) { if (iconInst == null || iconInst.iconOfParent) { continue; } Set<Global> excludeGlobals = null; if (iconInstExcludeGlobals != null) { excludeGlobals = iconInstExcludeGlobals.get(iconInst); } for (int k = 0; k < iconInst.iconNodables.length; k++) { EquivalentSchematicExports eq = iconInst.eq.implementation; assert eq.implementation == eq; int numGlobals = eq.portOffsets[0]; if (numGlobals == 0) { continue; } int nodableOffset = iconInst.netMapOffset + k * iconInst.numExtendedExports; for (int i = 0; i < numGlobals; i++) { Global g = eq.globals.get(i); if (excludeGlobals != null && excludeGlobals.contains(g)) { continue; } Netlist.connectMap(netMap, this.globals.indexOf(g), nodableOffset + i); } } } Netlist.closureMap(netMap); } private void pushName(Name name) { for (Iterator<Export> it = cell.getExports(); it.hasNext();) { Export e = it.next(); Name n = e.getNameKey(); for (int i = 0; i < n.busWidth(); i++) { if (n.subname(i) == name) { networkManager.pushHighlight(e); return; } } } for (Iterator<ArcInst> it = cell.getArcs(); it.hasNext();) { ArcInst ai = it.next(); Name n = ai.getNameKey(); for (int i = 0; i < n.busWidth(); i++) { if (n.subname(i) == name) { networkManager.pushHighlight(ai); return; } } } } private void connectWireCon(int[] netMap, NodeInst ni) { ArcInst ai1 = null; ArcInst ai2 = null; for (Iterator<Connection> it = ni.getConnections(); it.hasNext();) { Connection con = it.next(); ArcInst ai = con.getArc(); if (ai1 == null) { ai1 = ai; } else if (ai2 == null) { ai2 = ai; } else { String msg = "Network: Schematic " + cell + " has connector " + ni + " which merges more than two arcs"; System.out.println(msg); networkManager.pushHighlight(ni); networkManager.logError(msg, NetworkTool.errorSortNetworks); return; } } if (ai2 == null || ai1 == ai2) { return; } int large = getArcDrawn(ai1); int small = getArcDrawn(ai2); if (large < 0 || small < 0) { return; } if (drawnWidths[small] > drawnWidths[large]) { int temp = small; small = large; large = temp; } for (int i = 0; i < drawnWidths[large]; i++) { Netlist.connectMap(netMap, drawnOffsets[large] + i, drawnOffsets[small] + (i % drawnWidths[small])); } } private void internalConnections(int[] netMapF, int[] netMapP, int[] netMapA) { int numNodes = cell.getNumNodes(); for (int k = 0; k < numNodes; k++) { NodeInst ni = cell.getNode(k); int nodeOffset = ni_pi[k]; NodeProto np = ni.getProto(); if (!ni.isCellInstance()) { PrimitiveNode.Function fun = ni.getFunction(); if (fun == PrimitiveNode.Function.RESIST) { Netlist.connectMap(netMapP, drawnOffsets[drawns[nodeOffset]], drawnOffsets[drawns[nodeOffset + 1]]); Netlist.connectMap(netMapA, drawnOffsets[drawns[nodeOffset]], drawnOffsets[drawns[nodeOffset + 1]]); } else if (fun.isComplexResistor()) { Netlist.connectMap(netMapA, drawnOffsets[drawns[nodeOffset]], drawnOffsets[drawns[nodeOffset + 1]]); } continue; } IconInst iconInst = iconInsts[k]; if (iconInst != null) { continue; } Cell subCell = (Cell) np; assert !(subCell.isIcon() || subCell.isSchematic()); EquivPorts eq = cell.tree().getEquivPorts(); int[] eqN = eq.getEquivPortsN(); int[] eqP = eq.getEquivPortsP(); int[] eqA = eq.getEquivPortsA(); int numPorts = eq.getNumExports(); assert eqN.length == numPorts && eqP.length == numPorts && eqA.length == numPorts; for (int i = 0; i < numPorts; i++) { int di = drawns[nodeOffset + i]; if (di < 0) { continue; } int jN = eqN[i]; if (i != jN) { int dj = drawns[nodeOffset + jN]; if (dj >= 0) { Netlist.connectMap(netMapF, drawnOffsets[di], drawnOffsets[dj]); } } int jP = eqP[i]; if (i != jP) { int dj = drawns[nodeOffset + jP]; if (dj >= 0) { Netlist.connectMap(netMapP, drawnOffsets[di], drawnOffsets[dj]); } } int jA = eqA[i]; if (i != jA) { int dj = drawns[nodeOffset + jA]; if (dj >= 0) { Netlist.connectMap(netMapA, drawnOffsets[di], drawnOffsets[dj]); } } } } for (IconInst iconInst : iconInsts) { if (iconInst == null || iconInst.iconOfParent) { continue; } for (int k = 0; k < iconInst.iconNodables.length; k++) { EquivalentSchematicExports eq = iconInst.eq.implementation; assert eq.implementation == eq; int[] eqN = eq.getEquivPortsN(); int[] eqP = eq.getEquivPortsP(); int[] eqA = eq.getEquivPortsA(); int nodableOffset = iconInst.netMapOffset + k * iconInst.numExtendedExports; for (int i = 0; i < eqN.length; i++) { int io = nodableOffset + i; int jF = eqN[i]; if (i != jF) { Netlist.connectMap(netMapF, io, nodableOffset + jF); } int jP = eqP[i]; if (i != jP) { Netlist.connectMap(netMapP, io, nodableOffset + jP); } int jA = eqA[i]; if (i != jA) { Netlist.connectMap(netMapA, io, nodableOffset + jA); } } } } } private void buildNetworkLists(int[] netMapF) { netlistN = new NetlistImpl(this, equivPortsN.length, netMapF); int equivPortIndex = 0; for (int i = 0; i < globals.size(); i++) { Global global = globals.get(i); int netIndex = netlistN.getNetIndex(global); netlistN.addUserName(netIndex, global.getNameKey(), true); netlistN.setEquivPortIndexByNetIndex(equivPortIndex++, netIndex); } for (Iterator<Export> it = cell.getExports(); it.hasNext();) { Export e = it.next(); for (int busIndex = 0; busIndex < e.getNameKey().busWidth(); busIndex++) { netlistN.setEquivPortIndexByNetIndex(equivPortIndex++, netlistN.getNetIndex(e, busIndex)); } } for (Map.Entry<Name, GenMath.MutableInteger> e : netNames.entrySet()) { Name name = e.getKey(); int index = e.getValue().intValue(); if (index < 0 || index >= exportedNetNameCount) { continue; } netlistN.addUserName(netlistN.getNetIndexByMap(netNamesOffset + index), name, true); } for (Map.Entry<Name, GenMath.MutableInteger> e : netNames.entrySet()) { Name name = e.getKey(); int index = e.getValue().intValue(); if (index < exportedNetNameCount) { continue; } netlistN.addUserName(netlistN.getNetIndexByMap(netNamesOffset + index), name, false); } // add temporary names to unnamed nets int numArcs = cell.getNumArcs(), arcIndex = 0; for (Iterator<ArcInst> it = cell.getArcs(); arcIndex < numArcs; arcIndex++) { ArcInst ai = it.next(); int drawn = drawns[arcsOffset + arcIndex]; if (drawn < 0) { continue; } for (int j = 0; j < drawnWidths[drawn]; j++) { int netIndexN = netlistN.getNetIndex(ai, j); if (netIndexN >= 0 && netlistN.hasNames(netIndexN)) { netIndexN = -1; } if (netIndexN < 0) { continue; } if (drawnNames[drawn] == null) { continue; } String netName; if (drawnWidths[drawn] == 1) { netName = drawnNames[drawn].toString(); } else if (drawnNames[drawn].isTempname()) { int busIndex = NetworkTool.isBusAscendingInNetlistEngine() ? j : drawnWidths[drawn] - 1 - j; netName = drawnNames[drawn].toString() + "[" + busIndex + "]"; } else { netName = drawnNames[drawn].subname(j).toString(); } if (netIndexN >= 0) { netlistN.addTempName(netIndexN, netName); } } } // add temporary names to unconnected ports for (Iterator<Nodable> it = getNodables(); it.hasNext();) { Nodable no = it.next(); NodeProto np = no.getProto(); for (int i = 0, numPorts = np.getNumPorts(); i < numPorts; i++) { PortProto pp = np.getPort(i); for (int k = 0, busWidth = pp.getNameKey().busWidth(); k < busWidth; k++) { int netIndexN = netlistN.getNetIndex(no, pp, k); if (netIndexN >= 0 && !netlistN.hasNames(netIndexN)) { netlistN.addTempName(netIndexN, no.getName() + "." + pp.getNameKey().subname(k)); } } } } // add temporary names to unconnected ports for (int n = 0, numNodes = cell.getNumNodes(); n < numNodes; n++) { NodeInst ni = cell.getNode(n); NodeProto np = ni.getProto(); int arraySize = ni.getNameKey().busWidth(); for (int i = 0, numPorts = np.getNumPorts(); i < numPorts; i++) { PortProto pp = np.getPort(i); int drawn = drawns[ni_pi[n] + i]; if (drawn < 0) { continue; } int busWidth = pp.getNameKey().busWidth(); int drawnWidth = drawnWidths[drawn]; for (int l = 0; l < drawnWidth; l++) { int netIndexN = netlistN.getNetIndexByMap(drawnOffsets[drawn] + l); if (netIndexN >= 0 && !netlistN.hasNames(netIndexN)) { int arrayIndex = (l / busWidth) % arraySize; int busIndex = l % busWidth; netlistN.addTempName(netIndexN, ni.getNameKey().subname(arrayIndex) + "." + pp.getNameKey().subname(busIndex)); } } } } // check names and equivPortIndexByNetIndex map for (int i = 0, numNetworks = netlistN.getNumNetworks(); i < numNetworks; i++) { assert netlistN.hasNames(i); assert netlistN.isExported(i) == (i < netlistN.getNumExternalNetworks()); if (netlistN.isExported(i)) { int equivPortInd = netlistN.getEquivPortIndexByNetIndex(i); assert equivPortInd >= 0 && equivPortInd < equivPortIndex; } } /* // debug info System.out.println("BuildNetworkList "+cell); for (int kk = 0; kk < 2; kk++) { Netlist netlist; if (kk == 0) { netlist = netlistF; System.out.println("NetlistF"); } else { netlist = netlistT; System.out.println("NetlistT"); } int i = 0; for (int l = 0; l < netlist.networks.length; l++) { Network network = netlist.networks[l]; if (network == null) continue; String s = ""; for (Iterator<String> sit = network.getNames(); sit.hasNext(); ) { String n = sit.next(); s += "/"+ n; } System.out.println(" "+i+" "+s); i++; for (int k = 0; k < globals.size(); k++) { if (netlist.nm_net[netlist.netMap[k]] != l) continue; System.out.println("\t" + globals.get(k)); } int numPorts = cell.getNumPorts(); for (int k = 0; k < numPorts; k++) { Export e = (Export) cell.getPort(k); for (int j = 0; j < e.getNameKey().busWidth(); j++) { if (netlist.nm_net[netlist.netMap[portOffsets[k] + j]] != l) continue; System.out.println("\t" + e + " [" + j + "]"); } } for (int k = 0; k < numDrawns; k++) { for (int j = 0; j < drawnWidths[k]; j++) { int ind = drawnOffsets[k] + j; int netInd = netlist.netMap[ind]; if (netlist.nm_net[netlist.netMap[drawnOffsets[k] + j]] != l) continue; System.out.println("\tDrawn " + k + " [" + j + "]"); } } for (Iterator<NetName> it = netNames.values().iterator(); it.hasNext();) { NetName nn = it.next(); if (netlist.nm_net[netlist.netMap[netNamesOffset + nn.index]] != l) continue; System.out.println("\tNetName " + nn.name); } } } */ } /** * Update map of equivalent ports newEquivPort. */ private boolean updateInterface() { boolean changed = false; for (int i = 0; i < equivPortsN.length; i++) { if (equivPortsN[i] != netlistN.netMap[i]) { changed = true; equivPortsN[i] = netlistN.netMap[i]; } if (equivPortsP[i] != netlistP.netMap[i]) { changed = true; equivPortsP[i] = netlistP.netMap[i]; } if (equivPortsA[i] != netlistA.netMap[i]) { changed = true; equivPortsA[i] = netlistA.netMap[i]; } } return changed; } void updateSchematic() { synchronized (networkManager) { Snapshot oldSnapshot = expectedSnapshot.get(); Snapshot newSnapshot = database.backup(); if (oldSnapshot == newSnapshot) { return; } CellId cellId = cell.getId(); assert cellId.isIcon() || cellId.isSchematic(); // Check that old Netlists are still valid if (cellTree != newSnapshot.getCellTree(cellId) || mainSchemId != newSnapshot.getMainSchematics(cellId) || mainSchemId != cellId && mainSchemId != null && !eqExports.get(mainSchemId).equals(newSnapshot.getEquivExports(mainSchemId)) || !sameEqivPortsOfSubcells(newSnapshot, cell.getId())) { // clear errors for cell networkManager.startErrorLogging(cell); try { exportNameMapOffsets = null; makeDrawns(); // Gather port and arc names initNetnames(); redoNetworks1(); } finally { networkManager.finishErrorLogging(); } // Save info taht will help this this Netlists is still valid cellTree = newSnapshot.getCellTree(cellId); mainSchemId = newSnapshot.getMainSchematics(cellId); eqExports = new IdentityHashMap<CellId, EquivalentSchematicExports>(); if (mainSchemId != null) { eqExports.put(mainSchemId, newSnapshot.getEquivExports(mainSchemId)); } for (CellTree subTree : cellTree.getSubTrees()) { if (subTree == null) { continue; } CellId subCellId = subTree.top.cellRevision.d.cellId; if (subCellId.isIcon() || subCellId.isSchematic()) { eqExports.put(subCellId, newSnapshot.getEquivExports(subCellId)); } } } expectedSnapshot = new WeakReference<Snapshot>(newSnapshot); } } private boolean sameEqivPortsOfSubcells(Snapshot newSnapshot, CellId cellId) { for (CellTree subTree : newSnapshot.getCellTree(cellId).getSubTrees()) { if (subTree == null) { continue; } CellId subCellId = subTree.top.cellRevision.d.cellId; if (subCellId.isIcon()) { if (cellId.isSchematic() && newSnapshot.getCellGroupIndex(cellId) == newSnapshot.getCellGroupIndex(subCellId)) { // Icon of parent continue; } } else if (!subCellId.isSchematic()) { continue; } if (!newSnapshot.getEquivExports(subCellId).equals(eqExports.get(subCellId))) { return false; } } return true; } @Override boolean redoNetworks1() { // System.out.println("redoNetworks1 on " + cell); int numPorts = cell.getNumPorts(); if (portOffsets.length != numPorts + 1) { portOffsets = new int[numPorts + 1]; } /* Set index of NodeInsts */ if (drawnNames == null || drawnNames.length != numDrawns) { drawnNames = new Name[numDrawns]; drawnWidths = new int[numDrawns]; drawnOffsets = new int[numDrawns]; } calcDrawnWidths(); boolean changed = initNodables(); // Gather port and arc names int mapSize = netNamesOffset + netNames.size(); // HashMap/*<Cell,Netlist>*/ subNetlistsF = new HashMap/*<Cell,Netlist>*/(); // for (Iterator it = getNodables(); it.hasNext(); ) { // Nodable no = it.next(); // if (!no.isCellInstance()) continue; // Cell subCell = (Cell)no.getProto(); // subNetlistsF.put(subCell, networkManager.getNetlist(subCell, false)); // } int[] netMapF = Netlist.initMap(mapSize); localConnections(netMapF); // HashMap/*<Cell,Netlist>*/ subNetlistsT = new HashMap/*<Cell,Netlist>*/(); // for (Iterator<Nodable> it = getNodables(); it.hasNext(); ) { // Nodable no = it.next(); // if (!no.isCellInstance()) continue; // Cell subCell = (Cell)no.getProto(); // subNetlistsT.put(subCell, networkManager.getNetlist(subCell, true)); // } int[] netMapP = netMapF.clone(); int[] netMapA = netMapF.clone(); internalConnections(netMapF, netMapP, netMapA); buildNetworkLists(netMapF); assert equivPortsP.length == equivPortsN.length; netlistP = new NetlistShorted(netlistN, Netlist.ShortResistors.PARASITIC, netMapP); assert equivPortsA.length == equivPortsN.length; netlistA = new NetlistShorted(netlistN, Netlist.ShortResistors.ALL, netMapA); // if (updatePortImplementation()) { // changed = true; // } if (updateInterface()) { changed = true; } if (CHECK_EQUIV_PORTS) { EquivalentSchematicExports eq = cell.getDatabase().backup().getEquivExports(cell.getId()); // assert Arrays.equals(ni_pi, netSchem.ni_pi); // assert arcsOffset == netSchem.arcsOffset; // assert Arrays.equals(drawns, netSchem.drawns); // assert Arrays.equals(drawnWidths, netSchem.drawnWidths); // assert Arrays.equals(drawnNames, netSchem.drawnNames); // assert Arrays.equals(drawnOffsets, netSchem.drawnOffsets); // assert Arrays.equals(nodeOffsets, netSchem.nodeOffsets); assert globals.equals(eq.getGlobals()); // assert Arrays.equals(portOffsets, netSchem.portOffsets); assert Arrays.equals(equivPortsN, eq.getEquivPortsN()); assert Arrays.equals(equivPortsP, eq.getEquivPortsP()); assert Arrays.equals(equivPortsA, eq.getEquivPortsA()); } return changed; } /** * Update netlists to current Snapshot * Check if specified Netlist is no more fresh * @param netlist * @return true specified Netlist is no more fresh */ @Override boolean obsolete(Netlist netlist) { Netlist newNetlist = getNetlist(netlist.shortResistors); netlistN.expectedSnapshot = netlistP.expectedSnapshot = netlistA.expectedSnapshot = expectedSnapshot; return newNetlist != netlist; } }