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.
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Schematic.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.drc;
import com.sun.electric.database.geometry.EPoint;
import com.sun.electric.database.geometry.ERectangle;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Export;
import com.sun.electric.database.hierarchy.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.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.Geometric;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.database.variable.ElectricObject;
import com.sun.electric.database.variable.Variable;
import com.sun.electric.technology.PrimitiveNode;
import com.sun.electric.technology.technologies.Artwork;
import com.sun.electric.technology.technologies.Generic;
import com.sun.electric.technology.technologies.Schematics;
import com.sun.electric.tool.user.ErrorLogger;
import com.sun.electric.util.TextUtils;
import com.sun.electric.util.math.GenMath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Class to do schematic design-rule checking.
* Examines artwork of a schematic for sensibility.
*/
public class Schematic
{
// Cells, nodes and arcs
private Set nodesChecked = new HashSet();
private ErrorLogger errorLogger;
private Map> newVariables = new HashMap>();
public static void doCheck(ErrorLogger errorLog, Cell cell, Geometric[] geomsToCheck, DRC.DRCPreferences dp)
{
Schematic s = new Schematic();
s.errorLogger = errorLog;
s.checkSchematicCellRecursively(cell, geomsToCheck);
DRC.addDRCUpdate(0, null, null, null, null, s.newVariables, dp);
}
private Cell isACellToCheck(Geometric geo)
{
if (geo instanceof NodeInst)
{
NodeInst ni = (NodeInst)geo;
// ignore documentation icon
if (ni.isIconOfParent()) return null;
if (!ni.isCellInstance()) return null;
Cell subCell = (Cell)ni.getProto();
Cell contentsCell = subCell.contentsView();
if (contentsCell == null) contentsCell = subCell;
if (nodesChecked.contains(contentsCell)) return null;
return contentsCell;
}
return null;
}
private void checkSchematicCellRecursively(Cell cell, Geometric[] geomsToCheck)
{
nodesChecked.add(cell);
// ignore if not a schematic
if (!cell.isSchematic() && cell.getTechnology() != Schematics.tech())
return;
// recursively check contents in case of hierchically checking
if (geomsToCheck == null)
{
for(Iterator it = cell.getNodes(); it.hasNext(); )
{
NodeInst ni = it.next();
Cell contentsCell = isACellToCheck(ni);
if (contentsCell != null)
checkSchematicCellRecursively(contentsCell, geomsToCheck);
}
}
else
{
for (Geometric geo : geomsToCheck)
{
Cell contentsCell = isACellToCheck(geo);
if (contentsCell != null)
checkSchematicCellRecursively(contentsCell, geomsToCheck);
}
}
// now check this cell
System.out.println("Checking schematic " + cell);
ErrorGrouper eg = new ErrorGrouper(cell);
checkSchematicCell(cell, false, geomsToCheck, eg);
}
private int cellIndexCounter;
private class ErrorGrouper
{
private boolean inited;
private int cellIndex;
private Cell cell;
ErrorGrouper(Cell cell)
{
inited = false;
cellIndex = cellIndexCounter++;
this.cell = cell;
}
public int getSortKey()
{
if (!inited)
{
inited = true;
errorLogger.setGroupName(cellIndex, cell.getName());
}
return cellIndex;
}
}
private void checkSchematicCell(Cell cell, boolean justThis, Geometric[] geomsToCheck, ErrorGrouper eg)
{
int initialErrorCount = errorLogger.getNumErrors();
Netlist netlist = cell.getNetlist();
// Normal hierarchically geometry
if (geomsToCheck == null)
{
for(Iterator it = cell.getNodes(); it.hasNext(); )
{
NodeInst ni = it.next();
if (!ni.isCellInstance() &&
ni.getProto().getTechnology() == Generic.tech()) continue;
schematicDoCheck(netlist, ni, eg);
}
for(Iterator it = cell.getArcs(); it.hasNext(); )
{
ArcInst ai = it.next();
schematicDoCheck(netlist, ai, eg);
}
} else
{
for (Geometric geo : geomsToCheck)
schematicDoCheck(netlist, geo, eg);
}
checkCaseInsensitiveNetworks(netlist, eg);
checkArrayedIconsConflicts(cell, eg);
int errorCount = errorLogger.getNumErrors();
int thisErrors = errorCount - initialErrorCount;
String indent = " ";
if (justThis) indent = "";
if (thisErrors == 0) System.out.println(indent + "No errors found"); else
System.out.println(indent + thisErrors + " errors found");
if (justThis) errorLogger.termLogging(true);
}
/**
* Method to add all variables of a given NodeInst that must be added after Schematics DRC job is done.
*/
private void addVariable(NodeInst ni, Variable var)
{
List list = newVariables.get(ni);
if (list == null) // first time
{
list = new ArrayList();
newVariables.put(ni, list);
}
list.add(var);
}
/**
* Method to check schematic object "geom".
*/
private void schematicDoCheck(Netlist netlist, Geometric geom, ErrorGrouper eg)
{
// Checked already
if (nodesChecked.contains(geom))
return;
nodesChecked.add(geom);
Cell cell = geom.getParent();
if (geom instanceof NodeInst)
{
NodeInst ni = (NodeInst)geom;
NodeProto np = ni.getProto();
// check for bus pins that don't connect to any bus arcs
if (np == Schematics.tech().busPinNode)
{
// proceed only if it has no exports on it
if (!ni.hasExports())
{
// must not connect to any bus arcs
boolean found = false;
for(Iterator it = ni.getConnections(); it.hasNext(); )
{
Connection con = it.next();
if (con.getArc().getProto() == Schematics.tech().bus_arc) { found = true; break; }
}
if (!found)
{
errorLogger.logError("Bus pin does not connect to any bus arcs", geom, cell, null, eg.getSortKey());
return;
}
}
// make a list of all bus networks at the pin
Set onPin = new HashSet();
boolean hadBusses = false;
for(Iterator it = ni.getConnections(); it.hasNext(); )
{
Connection con = it.next();
ArcInst ai = con.getArc();
if (ai.getProto() != Schematics.tech().bus_arc) continue;
hadBusses = true;
int wid = netlist.getBusWidth(ai);
for(int i=0; i geomList = null;
for(Iterator it = ni.getConnections(); it.hasNext(); )
{
Connection con = it.next();
ArcInst ai = con.getArc();
if (ai.getProto() != Schematics.tech().wire_arc) continue;
Network net = netlist.getNetwork(ai, 0);
if (onPin.contains(net)) continue;
if (geomList == null) geomList = new ArrayList();
geomList.add(ai);
}
if (geomList != null)
{
geomList.add(ni);
String msg;
if (hadBusses) msg = "Wire arcs do not connect to bus through a bus pin"; else
msg = "Wire arcs do not connect to each other through a bus pin";
errorLogger.logMessage(msg, geomList, cell, eg.getSortKey(), true);
return;
}
}
// check all pins
if (np.getFunction().isPin())
{
// may be stranded if there are no exports or arcs
if (!ni.hasExports() && !ni.hasConnections())
{
// see if the pin has displayable variables on it
boolean found = false;
for(Iterator it = ni.getVariables(); it.hasNext(); )
{
Variable var = it.next();
if (var.isDisplay()) { found = true; break; }
}
if (!found)
{
errorLogger.logError("Stranded pin (not connected or exported)", geom, cell, null, eg.getSortKey());
return;
}
}
if (ni.isInlinePin())
{
errorLogger.logError("Unnecessary pin (between 2 arcs)", geom, cell, null, eg.getSortKey());
return;
}
Point2D pinLoc = ni.invisiblePinWithOffsetText(false);
if (pinLoc != null)
{
List geomList = new ArrayList();
List ptList = new ArrayList();
geomList.add(geom);
ptList.add(new EPoint(ni.getAnchorCenterX(), ni.getAnchorCenterY()));
ptList.add(new EPoint(pinLoc.getX(), pinLoc.getY()));
errorLogger.logMessageWithLines("Invisible pin has text in different location",
geomList, ptList, cell, eg.getSortKey(), true);
return;
}
}
// check parameters
if (np instanceof Cell)
{
Cell instCell = (Cell)np;
Cell contentsCell = instCell.contentsView();
if (contentsCell == null) contentsCell = instCell;
// ensure that this node matches the parameter list
for(Iterator it = ni.getDefinedParameters(); it.hasNext(); )
{
Variable var = it.next();
assert ni.isParam(var.getKey());
Variable foundVar = contentsCell.getParameter(var.getKey());
if (foundVar == null)
{
// this node's parameter is no longer on the cell: delete from instance
String trueVarName = var.getTrueName();
errorLogger.logError("Parameter '" + trueVarName + "' on " + ni +
" is invalid", geom, cell, null, eg.getSortKey());
} else
{
// this node's parameter is still on the cell: make sure units are OK
if (var.getUnit() != foundVar.getUnit())
{
String trueVarName = var.getTrueName();
errorLogger.logError("Parameter '" + trueVarName + "' on " + ni +
" had incorrect units (now fixed)", geom, cell, null, eg.getSortKey());
addVariable(ni, var.withUnit(foundVar.getUnit()));
}
// make sure visibility is OK
if (foundVar.isInterior())
{
if (var.isDisplay())
{
String trueVarName = var.getTrueName();
errorLogger.logError("Parameter '" + trueVarName + "' on " + ni +
" should not be visible (now fixed)", geom, cell, null, eg.getSortKey());
addVariable(ni, var.withDisplay(false));
}
} else
{
if (!var.isDisplay())
{
String trueVarName = var.getTrueName();
errorLogger.logError("Parameter '" + trueVarName + "' on " + ni +
" should be visible (now fixed)", geom, cell, null, eg.getSortKey());
addVariable(ni, var.withDisplay(true));
}
}
}
}
// make sure instance name isn't the same as a network in the cell
String nodeName = ni.getName();
for(Iterator it = netlist.getNetworks(); it.hasNext(); )
{
Network net = it.next();
if (net.hasName(nodeName))
{
errorLogger.logError("Node " + ni + " is named '" + nodeName +
"' which conflicts with a network name in this cell", geom, cell, null, eg.getSortKey());
break;
}
}
}
// check all exports for proper icon/schematics characteristics match
Cell parentCell = ni.getParent();
for(Iterator cIt = parentCell.getCellGroup().getCells(); cIt.hasNext(); )
{
Cell iconCell = cIt.next();
if (iconCell.getView() != View.ICON) continue;
for(Iterator it = ni.getExports(); it.hasNext(); )
{
Export e = it.next();
List allExports = e.findAllEquivalents(iconCell, false);
for(Export iconExport : allExports)
{
if (e.getCharacteristic() != iconExport.getCharacteristic())
{
errorLogger.logError("Export '" + e.getName() + "' on " + ni +
" is " + e.getCharacteristic().getFullName() +
" but export in icon cell " + iconCell.describe(false) + " is " +
iconExport.getCharacteristic().getFullName(), geom, cell, null, eg.getSortKey());
}
}
}
}
// check for port overlap
checkPortOverlap(netlist, ni, eg);
} else
{
ArcInst ai = (ArcInst)geom;
// check for being floating if it does not have a visible name on it
boolean checkDangle = false;
if (Artwork.isArtworkArc(ai.getProto()))
return; // ignore artwork arcs
Name arcName = ai.getNameKey();
if (arcName == null || arcName.isTempname()) checkDangle = true;
if (checkDangle)
{
// do not check for dangle when busses are on named networks
if (ai.getProto() == Schematics.tech().bus_arc)
{
Name name = netlist.getBusName(ai);
if (name != null && !name.isTempname()) checkDangle = false;
}
}
if (checkDangle)
{
// check to see if this arc is floating
for(int i=0; i<2; i++)
{
NodeInst ni = ai.getPortInst(i).getNodeInst();
// OK if not a pin
if (!ni.getProto().getFunction().isPin()) continue;
// OK if it has exports on it
if (ni.hasExports()) continue;
// OK if it connects to more than 1 arc
if (ni.getNumConnections() != 1) continue;
// the arc dangles
errorLogger.logError("Arc dangles", geom, cell, null, eg.getSortKey());
return;
}
}
// check to see if its width is sensible
int signals = netlist.getBusWidth(ai);
if (signals < 1) signals = 1;
for(int i=0; i<2; i++)
{
PortInst pi = ai.getPortInst(i);
NodeInst ni = pi.getNodeInst();
if (!ni.isCellInstance()) continue;
Cell subNp = (Cell)ni.getProto();
PortProto pp = pi.getPortProto();
Cell np = subNp.contentsView();
if (np != null)
{
pp = ((Export)pi.getPortProto()).findEquivalent(np);
if (pp == null || pp == pi.getPortProto())
{
List geomList = new ArrayList();
geomList.add(geom);
geomList.add(ni);
errorLogger.logMessage("Arc " + ai.describe(true) + " connects to " +
pi.getPortProto() + " of " + ni + ", but there is no equivalent port in " + np,
geomList, cell, eg.getSortKey(), true);
continue;
}
}
int portWidth = netlist.getBusWidth((Export)pp);
if (portWidth < 1) portWidth = 1;
int nodeSize = ni.getNameKey().busWidth();
if (nodeSize <= 0) nodeSize = 1;
if (signals != portWidth && signals != portWidth*nodeSize)
{
List geomList = new ArrayList();
geomList.add(geom);
geomList.add(ni);
errorLogger.logMessage("Arc " + ai.describe(true) + " (" + signals + " wide) connects to " +
pp + " of " + ni + " (" + portWidth + " wide)", geomList, cell, eg.getSortKey(), true);
}
}
// check to see if it covers a pin
Rectangle2D rect = ai.getBounds();
Network net = netlist.getNetwork(ai, 0);
for(Iterator sea = cell.searchIterator(rect); sea.hasNext(); )
{
Geometric oGeom = sea.next();
if (oGeom instanceof NodeInst)
{
NodeInst ni = (NodeInst)oGeom;
// must be a pin on an unconnected network
if (ni.getFunction() != PrimitiveNode.Function.PIN) continue;
if (ni.getProto().getTechnology() == Generic.tech()) continue;
Network oNet = netlist.getNetwork(ni.getOnlyPortInst());
if (net == oNet) continue;
// if it is an oversize bus pin, allow it
// Rectangle2D bound = ni.getBounds();
// if (bound.getWidth() > 0 || bound.getHeight() > 0) continue;
long[] gridCoords = new long[4];
((PrimitiveNode)ni.getProto()).genElibBounds(cell.getMemoization(), ni.getD(), gridCoords);
ERectangle bound = ERectangle.fromGrid(gridCoords[0], gridCoords[1],
gridCoords[2] - gridCoords[0], gridCoords[3] - gridCoords[1]);
if (bound.getGridWidth() > 0 || bound.getGridHeight() > 0) continue;
// Rectangle2D bound = ni.getBounds();
// if (ni.getProto() == Schematics.tech().busPinNode)
// {
// PrimitiveNode pnp = (PrimitiveNode)ni.getProto();
// ERectangle pBounds = pnp.getBaseRectangle();
// if (bound.getWidth() > pBounds.getWidth() || bound.getHeight() > pBounds.getHeight()) continue;
// }
// error if it is on the line of this arc
Point2D ctr = new Point2D.Double(bound.getCenterX(), bound.getCenterY());
if (GenMath.isOnLine(ai.getHeadLocation(), ai.getTailLocation(), ctr))
{
List geomList = new ArrayList();
geomList.add(ai);
geomList.add(ni);
errorLogger.logMessage("Pin " + ni.describe(false) + " touches arc " + ai.describe(true) + " but does not connect to it ",
geomList, cell, eg.getSortKey(), true);
}
}
}
}
}
/**
* Method to check whether any port on a node overlaps others without connecting.
*/
private void checkPortOverlap(Netlist netlist, NodeInst ni, ErrorGrouper eg)
{
if (ni.getProto().getTechnology() == Generic.tech() ||
ni.getProto().getTechnology() == Artwork.tech()) return;
Cell cell = ni.getParent();
for(Iterator it = ni.getPortInsts(); it.hasNext(); )
{
PortInst pi = it.next();
Network net = netlist.getNetwork(pi);
Rectangle2D bounds = pi.getPoly().getBounds2D();
for(Iterator sIt = cell.searchIterator(bounds); sIt.hasNext(); )
{
Geometric oGeom = sIt.next();
if (!(oGeom instanceof NodeInst)) continue;
NodeInst oNi = (NodeInst)oGeom;
if (ni == oNi) continue;
if (ni.getNodeIndex() > oNi.getNodeIndex()) continue;
if (oNi.getProto().getTechnology() == Generic.tech() ||
oNi.getProto().getTechnology() == Artwork.tech()) continue;
// see if ports touch
for(Iterator pIt = oNi.getPortInsts(); pIt.hasNext(); )
{
PortInst oPi = pIt.next();
Rectangle2D oBounds = oPi.getPoly().getBounds2D();
if (bounds.getMaxX() < oBounds.getMinX()) continue;
if (bounds.getMinX() > oBounds.getMaxX()) continue;
if (bounds.getMaxY() < oBounds.getMinY()) continue;
if (bounds.getMinY() > oBounds.getMaxY()) continue;
// see if they are connected
if (net == netlist.getNetwork(oPi)) continue;
// report the error
List geomList = new ArrayList();
geomList.add(ni);
geomList.add(oNi);
errorLogger.logMessage("Nodes '" + ni + "' '" + oNi + "' have touching ports that are not connected",
geomList, cell, eg.getSortKey(), true);
return;
}
}
}
}
private void checkCaseInsensitiveNetworks(Netlist netlist, ErrorGrouper eg) {
Cell cell = netlist.getCell();
HashMap canonicToNetwork = new HashMap();
for (Iterator it = netlist.getNetworks(); it.hasNext(); ) {
Network net = it.next();
for (Iterator sit = net.getNames(); sit.hasNext(); ) {
String s = sit.next();
String cs = TextUtils.canonicString(s);
Network net1 = canonicToNetwork.get(cs);
if (net1 == null ) {
canonicToNetwork.put(cs, net);
} else if (net1 != net) {
String message = "Network: Schematic " + cell.libDescribe() + " doesn't connect " + net + " and " + net1;
boolean sameName = net1.hasName(s);
if (sameName)
message += " Like-named Global and Export may be connected in future releases";
System.out.println(message);
List geomList = new ArrayList();
push(geomList, net);
push(geomList, net1);
errorLogger.logMessage(message, geomList, cell, eg.getSortKey(), sameName);
}
}
}
}
private void checkArrayedIconsConflicts(Cell cell, ErrorGrouper eg) {
IdentityHashMap name2node = new IdentityHashMap();
for (Iterator it = cell.getNodes(); it.hasNext(); ) {
NodeInst ni = it.next();
Name n = ni.getNameKey();
if (n.isTempname()) {
continue;
}
for (int arrayIndex = 0; arrayIndex < n.busWidth(); arrayIndex++) {
Name subName = n.subname(arrayIndex);
NodeInst oni = name2node.get(subName);
if (oni != null) {
String msg = "Network: " + cell + " has instances " + ni + " and "
+ oni + " with same name <" + subName + ">";
System.out.println(msg);
List geomList = Arrays.asList(ni, oni);
errorLogger.logMessage(msg, geomList, cell, eg.getSortKey(), true);
}
}
}
}
private void push(List geomList, Network net) {
Iterator eit = net.getExports();
if (eit.hasNext()) {
geomList.add(eit.next().getOriginalPort().getNodeInst());
return;
}
Iterator ait = net.getArcs();
if (ait.hasNext()) {
geomList.add(ait.next());
return;
}
Iterator pit = net.getPorts();
if (pit.hasNext()) {
geomList.add(pit.next().getNodeInst());
return;
}
}
}