All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.electric.tool.drc.Quick Maven / Gradle / Ivy

There is a newer version: 9.02-e
Show newest version
/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: Quick.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.*;
import com.sun.electric.database.geometry.bool.LayoutMerger;
import com.sun.electric.database.geometry.bool.LayoutMergerFactory;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Export;
import com.sun.electric.database.hierarchy.HierarchyEnumerator;
import com.sun.electric.database.hierarchy.Nodable;
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.PortOriginal;
import com.sun.electric.database.prototype.PortProto;
import com.sun.electric.database.text.TextUtils;
import com.sun.electric.database.topology.ArcInst;
import com.sun.electric.database.topology.Geometric;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.database.variable.VarContext;
import com.sun.electric.database.variable.Variable;
import com.sun.electric.technology.*;
import com.sun.electric.technology.technologies.Generic;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.user.ErrorLogger;
import com.sun.electric.util.ElapseTimer;
import com.sun.electric.util.math.DBMath;
import com.sun.electric.util.math.FixpTransform;
import com.sun.electric.util.math.MutableDouble;
import com.sun.electric.util.math.MutableInteger;

import java.awt.geom.Area;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.*;

/**
 * This is the "quick" DRC which does full hierarchical examination of the circuit.
 * 

* The "quick" DRC works as follows: * It first examines every primitive node and arc in the cell * For each layer on these objects, it examines everything surrounding it, even in subcells * R-trees are used to limit search. * Where cell instances are found, the contents are examined recursively * It next examines every cell instance in the cell * All other instances within the surrounding area are considered * When another instance is found, the two instances are examined for interaction * A cache is kept of instance pairs in specified configurations to speed-up arrays * All objects in the other instance that are inside the bounds of the first are considered * The other instance is hierarchically examined to locate primitives in the area of consideration * For each layer on each primitive object found in the other instance, * Examine the contents of the first instance for interactions about that layer *

* Since Electric understands connectivity, it uses this information to determine whether two layers * are connected or not. However, if such global connectivity is propagated in the standard Electric * way (placing numbers on exports, descending into the cell, and pulling the numbers onto local networks) * then it is not possible to decompose the DRC for multiple processors, since two different processors * may want to write global network information on the same local networks at once. *

* To solve this problem, the "quick" DRC determines how many instances of each cell exist. For every * network in every cell, an array is built that is as large as the number of instances of that cell. * This array contains the global network number for that each instance of the cell. The algorithm for * building these arrays is quick (1 second for a million-transistor chip) and the memory requirement * is not excessive (8 megabytes for a million-transistor chip). It uses the CheckInst and CheckProto * objects. * @author Steve Rubin, Gilda Garreton */ public class Quick { private CellLayersContainer cellLayersCon = new CellLayersContainer(); // check layers in each cell with valid DRC rules private HashMap checkInsts = null; private HashMap checkProtos = null; // private List instanceInteractionList = new ArrayList(); private Map> instanceInteractionMap = new HashMap>(); private HashMap networkLists = null; private HashMap minAreaLayerMap = new HashMap(); // For minimum area checking private HashMap enclosedAreaLayerMap = new HashMap(); // For enclosed area checking private HashMap spacingLayerMap = new HashMap(); // to detect holes using the area function private HashMap slotSizeLayerMap = new HashMap(); // For max length checking private DRC.CheckDRCJob job; // Reference to running job private DRC.DRCPreferences dp; private HashMap cellsMap = new HashMap(); // for cell caching private HashMap nodesMap = new HashMap(); // for node caching private GeometryHandler.GHMode mergeMode = GeometryHandler.GHMode.ALGO_SWEEP; // .ALGO_QTREE; private Map od2Layers = new HashMap(3); /** to control OD2 combination in the same die according to foundries */ public Quick(DRC.CheckDRCJob j, DRC.DRCPreferences dp, GeometryHandler.GHMode mode) { this.job = j; this.dp = dp; this.mergeMode = mode; } /** a NodeInst that is too tiny for its connection. */ private NodeInst tinyNodeInst; /** the other Geometric in "tiny" errors. */ private Geometric tinyGeometric; /** for tracking the time of good DRC. */ private HashSet goodSpacingDRCDate = new HashSet(); /** for tracking cells that need to clean good DRC vars */ private HashSet cleanSpacingDRCDate = new HashSet(); /** for tracking the time of good DRC. */ private HashSet goodAreaDRCDate = new HashSet(); /** for tracking cells that need to clean good DRC vars */ private HashSet cleanAreaDRCDate = new HashSet(); /** Top cell for DRC */ private Cell topCell; /** Miscellanous data for DRC */ private DRC.ReportInfo reportInfo; // /* for figuring out which layers are valid for DRC */ // To speed up the layer process private ValidationLayers validLayers; public static ErrorLogger checkDesignRules(DRC.DRCPreferences dp, Cell cell, Geometric[] geomsToCheck, boolean[] validity) { ErrorLogger errorLog = DRC.getDRCErrorLogger(true, null); checkDesignRules(errorLog, cell, geomsToCheck, validity, null, null, dp, GeometryHandler.GHMode.ALGO_SWEEP, false); return errorLog; } /** * This is the entry point for DRC. * * Method to do a hierarchical DRC check on cell "cell". * If "count" is zero, check the entire cell. * If "count" is nonzero, only check that many instances (in "nodesToCheck") and set the * entry in "validity" TRUE if it is DRC clean. * @param bounds if null, check entire cell. If not null, only check area in bounds. * @param drcJob * @param onlyArea */ public static void checkDesignRules(ErrorLogger errorLog, Cell cell, Geometric[] geomsToCheck, boolean[] validity, Rectangle2D bounds, DRC.CheckDRCJob drcJob, DRC.DRCPreferences dp, GeometryHandler.GHMode mode, boolean onlyArea) { Quick q = new Quick(drcJob, dp, mode); q.doCheck(errorLog, cell, geomsToCheck, validity, bounds, onlyArea); } // returns the number of errors found private void doCheck(ErrorLogger errorLog, Cell cell, Geometric[] geomsToCheck, boolean[] validity, Rectangle2D bounds, boolean onlyArea) { // Check if there are DRC rules for particular tech Technology tech = cell.getTechnology(); DRCRules rules = DRC.getRules(tech); // if checking specific instances, adjust options and processor count int count = (geomsToCheck != null) ? geomsToCheck.length : 0; reportInfo = new DRC.ReportInfo(errorLog, tech, dp, (count > 0)); ErrorLogger errorLogger = errorLog; // caching bits System.out.println("Running DRC with " + DRC.explainBits(reportInfo.activeSpacingBits, dp)); // Nothing to check for this particular technology if (rules == null || rules.getNumberOfRules() == 0) return /*errorLogger*/; topCell = cell; /* Especially important for minArea checking */ // cache valid layers for this technology validLayers = new ValidationLayers(reportInfo.errorLogger, topCell, rules); // clean out the cache of instances // instanceInteractionList.clear(); instanceInteractionMap.clear(); // determine if min area must be checked (if any layer got valid data) minAreaLayerMap.clear(); enclosedAreaLayerMap.clear(); spacingLayerMap.clear(); slotSizeLayerMap.clear(); cellsMap.clear(); nodesMap.clear(); // No incremental neither per Cell if (!dp.ignoreAreaCheck && reportInfo.errorTypeSearch != DRC.DRCCheckMode.ERROR_CHECK_CELL) { for(Iterator it = tech.getLayers(); it.hasNext(); ) { Layer layer = it.next(); // Storing min areas DRCTemplate minAreaRule = DRC.getMinValue(layer, DRCTemplate.DRCRuleType.MINAREA); if (minAreaRule != null) minAreaLayerMap.put(layer, minAreaRule); // Storing enclosed areas DRCTemplate enclosedAreaRule = DRC.getMinValue(layer, DRCTemplate.DRCRuleType.MINENCLOSEDAREA); if (enclosedAreaRule != null) enclosedAreaLayerMap.put(layer, enclosedAreaRule); // Storing spacing rules DRCTemplate spaceRule = DRC.getSpacingRule(layer, null, layer, null, true, -1, -1.0, -1.0); // UCONSPA, CONSPA or SPACING if (spaceRule != null) spacingLayerMap.put(layer, spaceRule); // Storing slot sizes DRCTemplate slotRule = DRC.getMinValue(layer, DRCTemplate.DRCRuleType.SLOTSIZE); if (slotRule != null) slotSizeLayerMap.put(layer, slotRule); } if (onlyArea) { int numErrors = checkMinAreaSlow(cell); if (numErrors == 0) goodAreaDRCDate.add(cell); else cleanAreaDRCDate.add(cell); System.out.println("Missing update in dates"); return /*errorLogger*/; } } // initialize all cells for hierarchical network numbering checkProtos = new HashMap(); checkInsts = new HashMap(); // initialize cells in tree for hierarchical network numbering Netlist netlist = cell.getNetlist(); CheckProto cp = checkEnumerateProtos(cell, netlist); // now recursively examine, setting information on all instances cp.hierInstanceCount = 1; reportInfo.checkTimeStamp = 0; checkEnumerateInstances(cell); ElapseTimer timer = ElapseTimer.createInstance().start(); System.out.print("Checking again hierarchy"); // Another hierarchy traverse .... CheckCellLayerEnumerator layerCellCheck = new CheckCellLayerEnumerator(cellLayersCon); HierarchyEnumerator.enumerateCell(topCell, VarContext.globalContext, layerCellCheck); timer.end(); System.out.println(" .... (" + timer+ ")"); // now allocate space for hierarchical network arrays //int totalNetworks = 0; networkLists = new HashMap(); for (Map.Entry e : checkProtos.entrySet()) { Cell libCell = e.getKey(); CheckProto subCP = e.getValue(); if (subCP.hierInstanceCount > 0) { // allocate net number lists for every net in the cell for(Iterator nIt = subCP.netlist.getNetworks(); nIt.hasNext(); ) { Network net = nIt.next(); Integer [] netNumbers = new Integer[subCP.hierInstanceCount]; for(int i=0; i nIt = libCell.getNodes(); nIt.hasNext(); ) { NodeInst ni = nIt.next(); NodeProto np = ni.getProto(); if (!ni.isCellInstance()) continue; // ignore documentation icons if (ni.isIconOfParent()) continue; CheckInst ci = checkInsts.get(ni); CheckProto ocp = getCheckProto((Cell)np); ci.offset = ocp.totalPerCell; } reportInfo.checkTimeStamp++; for(Iterator nIt = libCell.getNodes(); nIt.hasNext(); ) { NodeInst ni = nIt.next(); NodeProto np = ni.getProto(); if (!ni.isCellInstance()) continue; // ignore documentation icons if (ni.isIconOfParent()) continue; CheckProto ocp = getCheckProto((Cell)np); if (ocp.timeStamp != reportInfo.checkTimeStamp) { CheckInst ci = checkInsts.get(ni); ocp.timeStamp = reportInfo.checkTimeStamp; ocp.totalPerCell += subCP.hierInstanceCount * ci.multiplier; } } } // now fill in the hierarchical network arrays reportInfo.checkTimeStamp = 0; int checkNetNumber = 1; HashMap enumeratedNets = new HashMap(); for(Iterator nIt = cp.netlist.getNetworks(); nIt.hasNext(); ) { Network net = nIt.next(); enumeratedNets.put(net, new Integer(checkNetNumber)); checkNetNumber++; } checkEnumerateNetworks(cell, cp, 0, enumeratedNets); if (count <= 0) System.out.println("Found " + checkNetNumber + " networks"); // now search for DRC exclusion areas reportInfo.exclusionMap.clear(); accumulateExclusion(cell); // now do the DRC int logsFound = 0; // int totalErrors = 0; if (count == 0) { // just do full DRC here /*totalErrors =*/ checkThisCell(cell, 0, bounds); // sort the errors by layer errorLogger.sortLogs(); } else { // check only these "count" instances (either an incremental DRC or a quiet one...from Array command) if (validity == null) { // not a quiet DRC, so it must be incremental logsFound = errorLogger.getNumLogs(); } // @TODO missing counting this number of errors. checkTheseGeometrics(cell, count, geomsToCheck, validity); } // if (errorLogger != null) { // errorLogger.termLogging(true); // logsFound = errorLogger.getNumLogs() - logsFound; // } // -2 if cells and subcells are ok // Commentted out on May 2, 2006. Not sure why this condition is valid // If goodDRCDate contains information of DRC clean cells, it destroys that information -> wrong // if (totalErrors != 0 && totalErrors != -2) goodDRCDate.clear(); // some cells were sucessfully checked: save that information in the database // some cells don't have valid DRC date anymore and therefore they should be clean // This is only going to happen if job was not aborted. if ((job == null || !job.checkAbort())) { DRC.addDRCUpdate(reportInfo.activeSpacingBits, goodSpacingDRCDate, cleanSpacingDRCDate, goodAreaDRCDate, cleanAreaDRCDate, null, dp); } } /*************************** QUICK DRC CELL EXAMINATION ***************************/ /** * Method to check the contents of cell "cell" with global network index "globalIndex". * Returns positive if errors are found, zero if no errors are found, negative on internal error. * @param cell * @param globalIndex * @param bounds * @return positive number if errors are found, zero if no errors are found and check the cell, -1 if job was * aborted and -2 if cell is OK with DRC date stored. */ private int checkThisCell(Cell cell, int globalIndex, Rectangle2D bounds) { // Job aborted or scheduled for abort if (job != null && job.checkAbort()) return -1; // Cell already checked if (cellsMap.get(cell) != null) return (0); // Previous # of errors/warnings int prevErrors = 0; int prevWarns = 0; if (reportInfo.errorLogger != null) { prevErrors = reportInfo.errorLogger.getNumErrors(); prevWarns = reportInfo.errorLogger.getNumWarnings(); } cellsMap.put(cell, cell); // Check if cell doesn't have special annotation Variable drcVar = cell.getVar(DRC.DRC_ANNOTATION_KEY); if (drcVar != null) { assert(drcVar.getLength() == 1 && drcVar.getObject(0) instanceof String); String val = (String)drcVar.getObject(0); if (val.toUpperCase().equals("BLACK")) { // Skipping this one assert(reportInfo.totalSpacingMsgFound == 0); // get rid of this variable. return reportInfo.totalSpacingMsgFound; } } // first check all subcells boolean allSubCellsStillOK = true; Area area = reportInfo.exclusionMap.get(cell); for(Iterator it = cell.getNodes(); it.hasNext(); ) { if (job != null && job.checkAbort()) return -1; NodeInst ni = it.next(); NodeProto np = ni.getProto(); if (!ni.isCellInstance()) continue; // ignore documentation icons if (ni.isIconOfParent()) continue; // Check DRC exclusion regions if (area != null && area.contains(ni.getBounds())) continue; // excluded // ignore if not in the area Rectangle2D subBounds = bounds; // sept30 if (subBounds != null) { if (!ni.getBounds().intersects(bounds)) continue; FixpTransform trans = ni.rotateIn(); FixpTransform xTrnI = ni.translateIn(); trans.preConcatenate(xTrnI); subBounds = new Rectangle2D.Double(); subBounds.setRect(bounds); DBMath.transformRect(subBounds, trans); } CheckProto cp = getCheckProto((Cell)np); if (cp.cellChecked && !cp.cellParameterized) continue; // recursively check the subcell CheckInst ci = checkInsts.get(ni); int localIndex = globalIndex * ci.multiplier + ci.localIndex + ci.offset; int retval = checkThisCell((Cell)np, localIndex, subBounds); if (retval < 0) return retval; // if cell is in goodDRCDate it means it changes its date for some reason. // This happen when a subcell was reloaded and DRC again. The cell containing // the subcell instance must be re-DRC to make sure changes in subCell don't affect // the parent one. if (retval > 0 || goodSpacingDRCDate.contains(np)) allSubCellsStillOK = false; // if (retval > 0) // allSubCellsStillOK = false; } // prepare to check cell CheckProto cp = getCheckProto(cell); cp.cellChecked = true; boolean checkArea = (cell == topCell && !dp.ignoreAreaCheck && reportInfo.errorTypeSearch != DRC.DRCCheckMode.ERROR_CHECK_CELL); // if the cell hasn't changed since the last good check, stop now Date lastSpacingGoodDate = DRC.getLastDRCDateBasedOnBits(cell, true, reportInfo.activeSpacingBits, !reportInfo.inMemory); Date lastAreaGoodDate = DRC.getLastDRCDateBasedOnBits(cell, false, -1, !reportInfo.inMemory); if (allSubCellsStillOK && DRC.isCellDRCDateGood(cell, lastSpacingGoodDate) && (!checkArea || DRC.isCellDRCDateGood(cell, lastAreaGoodDate))) { return 0; } // announce progress ElapseTimer timer = ElapseTimer.createInstance().start(); System.out.println("Checking " + cell); // now look at every node and arc here reportInfo.totalSpacingMsgFound = 0; // Check the area first but only when is not incremental // Only for the most top cell if (checkArea) { // totalMsgFound = checkMinArea(cell); assert(reportInfo.totalSpacingMsgFound == 0); int totalAreaMsgFound = checkMinAreaSlow(cell); if (totalAreaMsgFound == 0) goodAreaDRCDate.add(cell); else cleanAreaDRCDate.add(cell); } // instanceInteractionList.clear(); // part4 instanceInteractionMap.clear(); // part4 for(Iterator it = cell.getNodes(); it.hasNext(); ) { if (job != null && job.checkAbort()) return -1; NodeInst ni = it.next(); if (bounds != null) { if (!ni.getBounds().intersects(bounds)) continue; } if (area != null) { if (area.contains(ni.getBounds())) { continue; } } boolean ret = (ni.isCellInstance()) ? checkCellInst(ni, globalIndex) : checkNodeInst(ni, globalIndex); if (ret) { reportInfo.totalSpacingMsgFound++; if (reportInfo.errorTypeSearch == DRC.DRCCheckMode.ERROR_CHECK_CELL) break; } } Technology cellTech = cell.getTechnology(); for(Iterator it = cell.getArcs(); it.hasNext(); ) { if (job != null && job.checkAbort()) return -1; ArcInst ai = it.next(); Technology tech = ai.getProto().getTechnology(); if (tech != cellTech) { DRC.createDRCErrorLogger(reportInfo, DRC.DRCErrorType.TECHMIXWARN, " belongs to " + tech.getTechName(), cell, 0, 0, null, null, ai, null, null, null, null); continue; } if (bounds != null) { if (!ai.getBounds().intersects(bounds)) continue; } if (checkArcInst(cp, ai, globalIndex)) { reportInfo.totalSpacingMsgFound++; if (reportInfo.errorTypeSearch == DRC.DRCCheckMode.ERROR_CHECK_CELL) break; } } // If message founds, then remove any possible good date // !allSubCellsStillOK disconnected on April 18, 2006. totalMsgFound should // dictate if this cell is re-marked. if (reportInfo.totalSpacingMsgFound > 0) // || !allSubCellsStillOK) { cleanSpacingDRCDate.add(cell); } else { // Only mark the cell when it passes with a new version of DRC or didn't have // the DRC bit on // If lastGoodDate == null, wrong bits stored or no date available. if (lastSpacingGoodDate == null) goodSpacingDRCDate.add(cell); } // if there were no errors, remember that if (reportInfo.errorLogger != null) { int localErrors = reportInfo.errorLogger.getNumErrors() - prevErrors; int localWarnings = reportInfo.errorLogger.getNumWarnings() - prevWarns; timer.end(); if (localErrors == 0 && localWarnings == 0) { System.out.println("\tNo errors/warnings found"); } else { if (localErrors > 0) System.out.println("\tFOUND " + localErrors + " ERRORS"); if (localWarnings > 0) System.out.println("\tFOUND " + localWarnings + " WARNINGS"); } if (Job.getDebug()) System.out.println("\t(took " + timer + ")"); } return reportInfo.totalSpacingMsgFound; } /** * Check Poly for CIF Resolution Errors * @param poly * @param cell * @param geom * @return true if an error was found. */ private boolean checkResolution(PolyBase poly, Cell cell, Geometric geom) { double minAllowedResolution = reportInfo.minAllowedResolution.getLambda(); if (minAllowedResolution == 0) return false; int count = 0; String resolutionError = ""; Point2D [] points = poly.getPoints(); for(Point2D point : points) { if (DBMath.hasRemainder(point.getX(), minAllowedResolution)) { count++; resolutionError = TextUtils.formatDistance(Math.abs(((point.getX()/minAllowedResolution) % 1) * minAllowedResolution)) + "(X=" + point.getX() + ")"; break; // with one error is enough } else if (DBMath.hasRemainder(point.getY(), minAllowedResolution)) { count++; resolutionError = TextUtils.formatDistance(Math.abs(((point.getY()/minAllowedResolution) % 1) * minAllowedResolution)) + "(Y=" + point.getY() + ")"; break; } } if (count == 0) return false; // no error // there was an error, for now print error Layer layer = poly.getLayer(); DRC.createDRCErrorLogger(reportInfo,DRC.DRCErrorType.RESOLUTION, " resolution of " + resolutionError + " less than " + minAllowedResolution + " on layer " + layer.getName(), cell, 0, 0, "Resolution", null, geom, null, null, null, null); return true; } /** * Private method to check if geometry is covered 100% by exclusion region * @param geo * @return true if geometry is covered by exclusion */ private boolean coverByExclusion(Geometric geo) { Cell cell = geo.getParent(); Area area = reportInfo.exclusionMap.get(cell); if (area != null && area.contains(geo.getBounds())) { // System.out.println("DRC Exclusion found"); return true; } return false; } /** * Private method to check if geometry given by Poly object is inside an exclusion region * @param poly * @param parent * @return true if Poly is inside an exclusion region */ private boolean coverByExclusion(Poly poly, Cell parent) { Area area = reportInfo.exclusionMap.get(parent); if (area == null) return false; Point2D[] pts = poly.getPoints(); for (Point2D point : pts) { if (!area.contains(point)) { return false; } } return true; } /** * Method to check the design rules about nodeinst "ni". * @param ni * @param globalIndex * @return true if an error was found. */ private boolean checkNodeInst(NodeInst ni, int globalIndex) { Cell cell = ni.getParent(); Netlist netlist = getCheckProto(cell).netlist; NodeProto np = ni.getProto(); Technology tech = np.getTechnology(); FixpTransform trans = ni.rotateOut(); boolean errorsFound = false; // Skipping special nodes if (NodeInst.isSpecialNode(ni)) return false; // Oct 5; if (!np.getTechnology().isLayout()) return (false); // only layout nodes if (np.getFunction().isPin()) return false; // Sept 30 if (coverByExclusion(ni)) return false; // no errors // Already done if (nodesMap.get(ni) != null) return (false); nodesMap.put(ni, ni); if (DRC.checkNodeAgainstCombinationRules(ni, reportInfo)) { if (reportInfo.errorTypeSearch == DRC.DRCCheckMode.ERROR_CHECK_CELL) return true; errorsFound = true; } // if (np instanceof PrimitiveNode) // { // DRCTemplate forbidRule = // DRC.isForbiddenNode(((PrimitiveNode)np).getPrimNodeIndexInTech(), -1, // DRCTemplate.DRCRuleType.FORBIDDEN, tech); // if (forbidRule != null) // { // DRC.createDRCErrorLogger(reportInfo, DRC.DRCErrorType.FORBIDDEN, " is not allowed by selected foundry", cell, // -1, -1, forbidRule.nodeName, null, ni, null, null, null, null); // if (reportInfo.errorTypeSearch == DRC.DRCCheckMode.ERROR_CHECK_CELL) return true; // errorsFound = true; // } // } // get layers from the NodeInst. Not a cell at this point. // get all of the polygons on this node Poly [] nodeInstPolyList = DRC.getShapeOfNodeBasedOnRules(tech, reportInfo, ni); convertPseudoLayers(ni, nodeInstPolyList); int tot = nodeInstPolyList.length; boolean isTransistor = np.getFunction().isTransistor(); Technology.MultiCutData multiCutData = tech.getMultiCutData(ni); // examine the polygons on this node for(int j=0; j return regarless errorTypeSearch return true; } poly.transform(trans); // Checking resolution only after transformation ret = checkResolution(poly, cell, ni); if (ret) { if (reportInfo.errorTypeSearch == DRC.DRCCheckMode.ERROR_CHECK_CELL) return true; errorsFound = true; } // determine network for this polygon int netNumber = getDRCNetNumber(netlist, poly.getPort(), ni, globalIndex); ret = badBox(poly, layer, netNumber, tech, ni, trans, cell, globalIndex, multiCutData); if (ret) { if (reportInfo.errorTypeSearch == DRC.DRCCheckMode.ERROR_CHECK_CELL) return true; errorsFound = true; } ret = checkMinWidth(ni, layer, poly, tot==1); if (ret) { if (reportInfo.errorTypeSearch == DRC.DRCCheckMode.ERROR_CHECK_CELL) return true; errorsFound = true; } // Check select over transistor poly // Assumes polys on transistors fulfill condition by construction // ret = !isTransistor && checkSelectOverPolysilicon(ni, layer, poly, cell); ret = !isTransistor && checkExtensionRules(ni, layer, poly, cell); if (ret) { if (reportInfo.errorTypeSearch == DRC.DRCCheckMode.ERROR_CHECK_CELL) return true; errorsFound = true; } if (validLayers.isABadLayer(tech, layer.getIndex())) { DRC.createDRCErrorLogger(reportInfo, DRC.DRCErrorType.BADLAYERERROR, null, cell, 0, 0, null, poly, ni, layer, null, null, null); if (reportInfo.errorTypeSearch == DRC.DRCCheckMode.ERROR_CHECK_CELL) return true; errorsFound = true; } } // check node for minimum size if (DRC.checkNodeSize(ni, cell, reportInfo)) errorsFound = true; return errorsFound; } /** * Method to check the design rules about arcinst "ai". * Returns true if errors were found. */ private boolean checkArcInst(CheckProto cp, ArcInst ai, int globalIndex) { // ignore arcs with no topology Network net = cp.netlist.getNetwork(ai, 0); if (net == null) return false; Integer [] netNumbers = networkLists.get(net); if (nodesMap.get(ai) != null) { if (Job.LOCALDEBUGFLAG) System.out.println("Done already arc " + ai.getName()); return (false); } nodesMap.put(ai, ai); // Check if arc is contained in exclusion region // if (coverByExclusion(ai)) // return false; // no error boolean errorsFound = false; // Checking if the arc is horizontal or vertical Point2D from = ai.getHeadLocation(); Point2D to = ai.getTailLocation(); if (!DBMath.areEquals(from.getX(), to.getX()) && !DBMath.areEquals(from.getY(), to.getY())) { DRC.createDRCErrorLogger(reportInfo, DRC.DRCErrorType.CROOKEDERROR, null, ai.getParent(), -1, -1, null, null, ai, null, null, null, null); if (reportInfo.errorTypeSearch == DRC.DRCCheckMode.ERROR_CHECK_CELL) return true; errorsFound = true; } Technology tech = ai.getProto().getTechnology(); // get all of the polygons on this arc Poly [] arcInstPolyList = DRC.getShapeOfArcBasedOnRules(tech, ai); // Check resolution before cropping the for(Poly poly : arcInstPolyList) { Layer layer = poly.getLayer(); if (layer == null) continue; if (layer.isNonElectrical()) continue; // Checking resolution boolean ret = checkResolution(poly, ai.getParent(), ai); if (ret) { if (reportInfo.errorTypeSearch == DRC.DRCCheckMode.ERROR_CHECK_CELL) return true; errorsFound = true; } } DRC.cropActiveArc(ai, reportInfo.ignoreCenterCuts, arcInstPolyList); int tot = arcInstPolyList.length; // examine the polygons on this arc for(int j=0; j it = ni.getParent().searchIterator(searchBounds); it.hasNext(); ) { Geometric geom = it.next(); if ( geom == ni ) continue; // covered by checkInteraction? if (!(geom instanceof NodeInst)) continue; NodeInst oNi = (NodeInst)geom; // only check other nodes that are numerically higher (so each pair is only checked once) if (oNi.getNodeIndex() <= ni.getNodeIndex()) continue; if (!oNi.isCellInstance()) continue; CheckProto cpoNi = getCheckProto((Cell)oNi.getProto()); // assume oNi is a cell // see if this configuration of instances has already been done if (DRC.checkInteraction(instanceInteractionMap, reportInfo.errorTypeSearch, ni, ni, cpNi.cellParameterized, oNi, oNi, cpoNi.cellParameterized, ni, searchBounds)) continue; // found other instance "oNi", look for everything in "ni" that is near it Rectangle2D nearNodeBounds = oNi.getBounds(); // double worstInteractionDistanceLocal = worstInteractionDistance; if (!cellLayersCon.getWorstSpacingDistance(oNi.getProto(), mutableDist)) { // System.out.println("No worst spacing distance found in Quick:checkCellInst"); continue; } double worstInteractionDistanceLocal = mutableDist.doubleValue(); Rectangle2D subBounds = new Rectangle2D.Double( nearNodeBounds.getMinX()-worstInteractionDistanceLocal, nearNodeBounds.getMinY()-worstInteractionDistanceLocal, nearNodeBounds.getWidth() + worstInteractionDistanceLocal*2, nearNodeBounds.getHeight() + worstInteractionDistanceLocal*2); // recursively search instance "ni" in the vicinity of "oNi" boolean ret = checkCellInstContents(subBounds, ni, upTrans, localIndex, oNi, null, globalIndex, null); if (ret) errorFound = true; } return errorFound; } /** * Method to recursively examine the area "bounds" in cell "cell" with global index "globalIndex". * The objects that are found are transformed by "uptrans" to be in the space of a top-level cell. * They are then compared with objects in "oNi" (which is in that top-level cell), * which has global index "topGlobalIndex". */ private boolean checkCellInstContents(Rectangle2D bounds, NodeInst thisNi, FixpTransform upTrans, int globalIndex, NodeInst oNi, NodeInst oNiParent, int topGlobalIndex, NodeInst triggerNi) { // Job aborted or scheduled for abort if (job != null && job.checkAbort()) return true; Cell cell = (Cell)thisNi.getProto(); if (!cell.isLayout()) return false; // skips non-layout cells. CheckProto cpoNi = getCheckProto((Cell)oNi.getProto()); // assume oNi is a cell boolean logsFound = false; Netlist netlist = getCheckProto(cell).netlist; Technology cellTech = cell.getTechnology(); // Need to transform bounds coordinates first otherwise it won't // never overlap Rectangle2D bb = (Rectangle2D)bounds.clone(); FixpTransform downTrans = thisNi.transformIn(); DBMath.transformRect(bb, downTrans); for(Iterator it = cell.searchIterator(bb); it.hasNext(); ) { Geometric geom = it.next(); // Checking if element is covered by exclusion region // if (coverByExclusion(geom)) // continue; // skips this element if (geom instanceof NodeInst) { NodeInst ni = (NodeInst)geom; NodeProto np = ni.getProto(); if (NodeInst.isSpecialNode(ni)) continue; // Oct 5'04 if (ni.isCellInstance()) { CheckProto cpNi = getCheckProto((Cell)np); // see if this configuration of instances has already been done if (DRC.checkInteraction(instanceInteractionMap, reportInfo.errorTypeSearch, ni, thisNi, cpNi.cellParameterized, oNi, oNiParent, cpoNi.cellParameterized, triggerNi, bb)) continue; // Jan 27'05. Removed on May'05 // You can't discard by interaction becuase two cells could be visited many times // during this type of checking FixpTransform subUpTrans = ni.translateOut(ni.rotateOut()); subUpTrans.preConcatenate(upTrans); CheckInst ci = checkInsts.get(ni); int localIndex = globalIndex * ci.multiplier + ci.localIndex + ci.offset; // changes Sept04: subBound by bb boolean ret = checkCellInstContents(bb, ni, subUpTrans, localIndex, oNi, oNiParent, topGlobalIndex, (triggerNi==null)?ni:triggerNi); if (ret) { if (reportInfo.errorTypeSearch == DRC.DRCCheckMode.ERROR_CHECK_CELL) return true; logsFound = true; } } else { Technology tech = np.getTechnology(); Poly [] primPolyList = DRC.getShapeOfNodeBasedOnRules(tech, reportInfo, ni); convertPseudoLayers(ni, primPolyList); int tot = primPolyList.length; if (tot == 0) continue; Technology.MultiCutData multiCutData = tech.getMultiCutData(ni); FixpTransform rTrans = ni.rotateOut(); rTrans.preConcatenate(upTrans); for(int j=0; j it = cell.searchIterator(bounds); it.hasNext(); ) { Geometric nGeom = it.next(); // I have to check if they are the same instance otherwise I check geometry against itself if (nGeom == geom && (sameInstance))// || nGeom.getParent() == cell)) continue; // Checking if element is covered by exclusion region if (coverByExclusion(nGeom)) continue; // skips this element if (nGeom instanceof NodeInst) { NodeInst ni = (NodeInst)nGeom; NodeProto np = ni.getProto(); if (NodeInst.isSpecialNode(ni)) continue; // Oct 5; // ignore nodes that are not primitive if (ni.isCellInstance()) { // instance found: look inside it for offending geometry FixpTransform rTransI = ni.rotateIn(); FixpTransform tTransI = ni.translateIn(); rTransI.preConcatenate(tTransI); subBound.setRect(bounds); DBMath.transformRect(subBound, rTransI); CheckInst ci = checkInsts.get(ni); int localIndex = cellGlobalIndex * ci.multiplier + ci.localIndex + ci.offset; FixpTransform subTrans = ni.translateOut(ni.rotateOut()); subTrans.preConcatenate(upTrans); //Sept 15 04 // compute localIndex if (badBoxInArea(poly, layer, tech, net, geom, trans, globalIndex, subBound, (Cell)np, localIndex, topCell, topGlobalIndex, subTrans, multiCutData, sameInstance)) { foundError = true; if (reportInfo.errorTypeSearch != DRC.DRCCheckMode.ERROR_CHECK_EXHAUSTIVE) return true; } } else { // don't check between technologies if (np.getTechnology() != tech) continue; // see if this type of node can interact with this layer if (!validLayers.checkLayerWithNode(layer, np)) continue; // see if the objects directly touch but they are not // coming from different NodeInst (not from checkCellInstContents // because they might below to the same cell but in different instances boolean touch = sameInstance && nGeom.isConnected(geom); // get the shape of each nodeinst layer Poly [] subPolyList = DRC.getShapeOfNodeBasedOnRules(tech, reportInfo, ni); int tot = subPolyList.length; if (tot == 0) System.out.println("Should i skup this one?"); convertPseudoLayers(ni, subPolyList); // prepare to examine every layer in this nodeinst FixpTransform rTrans = ni.rotateOut(); rTrans.preConcatenate(upTrans); for(int i=0; i=1 if (multiCutData == null || multiCutData.numCutsX() == 1) // it is 1xn { // Checking if they match at the Y axis. If yes, they are considered as a long 1xn array // so multi=false. The other element must be 1xM if (niMCD.numCutsY() != 1 && ni.getAnchorCenterX() != gNi.getAnchorCenterX()) multi = true; } else { // Checking if they match at the Y axis. If yes, they are considered as a long 1xn array // so multi=false if (niMCD.numCutsX() != 1 && ni.getAnchorCenterY() != gNi.getAnchorCenterY()) multi = true; } } } int multiInt = (multi) ? 1 : 0; for(int j=0; j=0) { con = (nNet == net); if (!con && net == -1) // geom is a resitor con = isConnectedToResistor(netlist, cellGlobalIndex, tech, nLayer, nNet, layer, geom); } else con = isConnectedToResistor(netlist, cellGlobalIndex, tech, layer, net, nLayer, ni); // Checking extension, it could be slow boolean ret = checkExtensionGateRule(geom, layer, poly, nLayer, npoly, netlist); if (ret) { foundError = true; if (reportInfo.errorTypeSearch != DRC.DRCCheckMode.ERROR_CHECK_EXHAUSTIVE) return true; } // check if both polys are cut and if the combine area doesn't excess cut sizes // regardless if they are connected or not ret = checkCutSizes(np, geom, layer, poly, nGeom, nLayer, npoly, topCell); if (ret) { foundError = true; if (reportInfo.errorTypeSearch != DRC.DRCCheckMode.ERROR_CHECK_EXHAUSTIVE) return true; } // if they connect electrically and adjoin, don't check if (con && touch) { // Check if there are minimum size defects boolean maytouch = DRC.mayTouch(tech, con, layer, nLayer); Rectangle2D trueBox1 = poly.getBox(); if (trueBox1 == null) trueBox1 = poly.getBounds2D(); Rectangle2D trueBox2 = npoly.getBox(); if (trueBox2 == null) trueBox1 = npoly.getBounds2D(); ret = checkMinDefects(cell,maytouch, geom, poly, trueBox1, layer, nGeom, npoly, trueBox2, nLayer, topCell); if (ret) { foundError = true; if (reportInfo.errorTypeSearch != DRC.DRCCheckMode.ERROR_CHECK_EXHAUSTIVE) return true; } continue; } boolean edge = false; // @TODO check if previous spacing rule was composed of same layers! DRCTemplate theRule = getSpacingRule(layer, poly, geom, nLayer, npoly, ni, con, multiInt); // Try edge rules if (theRule == null) { theRule = DRC.getEdgeRule(layer, nLayer); edge = true; } if (theRule == null) continue; ret = checkDist(tech, topCell, topGlobalIndex, poly, layer, net, geom, trans, globalIndex, npoly, nLayer, nNet, nGeom, rTrans, cellGlobalIndex, con, theRule, edge); if (ret) { foundError = true; if (reportInfo.errorTypeSearch != DRC.DRCCheckMode.ERROR_CHECK_EXHAUSTIVE) return true; } } } } else { ArcInst ai = (ArcInst)nGeom; ArcProto ap = ai.getProto(); // don't check between technologies if (ap.getTechnology() != tech) continue; // see if this type of arc can interact with this layer if (!validLayers.checkLayerWithArc(layer, ap)) continue; // see if the objects directly touch boolean touch = sameInstance && nGeom.isConnected(geom); // see whether the two objects are electrically connected Network jNet = netlist.getNetwork(ai, 0); Integer [] netNumbers = networkLists.get(jNet); int nNet = netNumbers[cellGlobalIndex].intValue(); boolean con = false; if (net >= 0 && nNet == net) con = true; // if they connect electrically and adjoin, don't check // if (con && touch) continue; // get the shape of each arcinst layer // Poly [] subPolyList = tech.getShapeOfArc(ai); Poly [] subPolyList = DRC.getShapeOfArcBasedOnRules(tech, ai); int tot = subPolyList.length; for(int i=0; i rBound.getMaxX() || nPolyRect.getMaxX() < rBound.getMinX() || nPolyRect.getMinY() > rBound.getMaxY() || nPolyRect.getMaxY() < rBound.getMinY()) continue; boolean ret = false; // try the resistor part if (!con) con = isConnectedToResistor(netlist, cellGlobalIndex, tech, nLayer, nNet, layer, geom); // if they connect electrically and adjoin, don't check // We must check if there are minor defects if they overlap regardless if they are connected or not if (con && touch) { // Check if there are minimum size defects boolean maytouch = DRC.mayTouch(tech, con, layer, nLayer); Rectangle2D trueBox1 = poly.getBox(); if (trueBox1 == null) trueBox1 = poly.getBounds2D(); Rectangle2D trueBox2 = nPoly.getBox(); if (trueBox2 == null) trueBox1 = nPoly.getBounds2D(); ret = checkMinDefects(cell, maytouch, geom, poly, trueBox1, layer, nGeom, nPoly, trueBox2, nLayer, topCell); if (ret) { foundError = true; if (reportInfo.errorTypeSearch != DRC.DRCCheckMode.ERROR_CHECK_EXHAUSTIVE) return true; } continue; } // see how close they can get boolean edge = false; DRCTemplate theRule = getSpacingRule(layer, poly, geom, nLayer, nPoly, ai, con, multiInt); if (theRule == null) { theRule = DRC.getEdgeRule(layer, nLayer); edge = true; } if (theRule == null) continue; // check the distance ret = checkDist(tech, topCell, topGlobalIndex, poly, layer, net, geom, trans, globalIndex, nPoly, nLayer, nNet, nGeom, upTrans, cellGlobalIndex, con, theRule, edge); if (ret) { foundError = true; if (reportInfo.errorTypeSearch != DRC.DRCCheckMode.ERROR_CHECK_EXHAUSTIVE) return true; } // Checking extension, it could be slow ret = checkExtensionGateRule(geom, layer, poly, nLayer, nPoly, netlist); if (ret) { foundError = true; if (reportInfo.errorTypeSearch != DRC.DRCCheckMode.ERROR_CHECK_EXHAUSTIVE) return true; } } } } return foundError; } /** * Function to detect small edges due to overlapping polygons of the same material. It is valid only * for manhattan shapes * @return true if error was found */ private boolean checkMinDefects(Cell cell, boolean maytouch, Geometric geom1, Poly poly1, Rectangle2D trueBox1, Layer layer1, Geometric geom2, Poly poly2, Rectangle2D trueBox2, Layer layer2, Cell topCell) { if (trueBox1 == null || trueBox2 == null) return false; if (!maytouch) return false; // manhattan double pdx = DBMath.round(Math.max(trueBox2.getMinX()-trueBox1.getMaxX(), trueBox1.getMinX()-trueBox2.getMaxX())); double pdy = DBMath.round(Math.max(trueBox2.getMinY()-trueBox1.getMaxY(), trueBox1.getMinY()-trueBox2.getMaxY())); double pd = Math.max(pdx, pdy); if (DBMath.areEquals(pdx, 0) && DBMath.areEquals(pdy, 0)) pd = 0; // touching boolean foundError = false; // They have to overlap if (DBMath.isGreaterThan(pd, 0)) return false; // they are electrically connected and they overlap: look for minimum size errors // of the overlapping region. DRCTemplate wRule = DRC.getMinValue(layer1, DRCTemplate.DRCRuleType.MINWID); if (wRule == null) return false; // no rule double minWidth = wRule.getValue(0); double lxb = DBMath.round(Math.max(trueBox1.getMinX(), trueBox2.getMinX())); double hxb = DBMath.round(Math.min(trueBox1.getMaxX(), trueBox2.getMaxX())); double lyb = DBMath.round(Math.max(trueBox1.getMinY(), trueBox2.getMinY())); double hyb = DBMath.round(Math.min(trueBox1.getMaxY(), trueBox2.getMaxY())); Point2D lowB = new Point2D.Double(lxb, lyb); Point2D highB = new Point2D.Double(hxb, hyb); Rectangle2D bounds = new Rectangle2D.Double(lxb, lyb, hxb-lxb, hyb-lyb); // If resulting bounding box is identical to one of the original polygons // then one polygon is contained in the other one if (bounds.equals(trueBox1) || bounds.equals(trueBox2)) { return false; } //+-------------------+F //| | //| | //| |B E //| +-------+---------+ //| | | | //|C A| | | //+-----------+-------+ | // | | // D+-----------------+ // Checking A-B distance double actual = lowB.distance(highB); // !DBMath.areEquals(actual, 0) is on, it skips cases where A==B. // Condition off as of July 2nd 2008. Bugzilla 1745 if (/*!DBMath.areEquals(actual, 0) &&*/ DBMath.isGreaterThan(minWidth, actual) && foundSmallSizeDefect(cell, geom1, poly1, layer1, geom2, poly2, pd, lxb, lyb, hxb, hyb)) { // you can't pass geom1 or geom2 becuase they could be in different cells and therefore the message // could mislead DRC.createDRCErrorLogger(reportInfo, DRC.DRCErrorType.MINWIDTHERROR, null, topCell, minWidth, actual, wRule.ruleName, new Poly(bounds), null, layer1, null, null, layer2); foundError = true; } return foundError; } private boolean foundSmallSizeDefect(Cell cell, Geometric geom1, Poly poly1, Layer layer1, Geometric geom2, Poly poly2, double pd, double lxb, double lyb, double hxb, double hyb) { boolean foundError = false; boolean [] pointsFound = new boolean[2]; pointsFound[0] = pointsFound[1] = false; Point2D lowB = new Point2D.Double(lxb, lyb); Point2D highB = new Point2D.Double(hxb, hyb); Rectangle2D bounds = new Rectangle2D.Double(lxb, lyb, hxb-lxb, hyb-lyb); Poly rebuild = new Poly(bounds); Point2D pt1 = null; //new Point2D.Double(lxb-TINYDELTA, lyb-TINYDELTA); Point2D pt2 = null; //new Point2D.Double(lxb-TINYDELTA, hyb+TINYDELTA); Point2D pt1d = null;//(Point2D)pt1.clone(); Point2D pt2d = null; //(Point2D)pt2.clone(); // Search area should be bigger than bounding box otherwise it might not get the cells due to // rounding errors. Rectangle2D search = new Rectangle2D.Double(DBMath.round(lxb- DRC.TINYDELTA), DBMath.round(lyb- DRC.TINYDELTA), DBMath.round(hxb-lxb+2* DRC.TINYDELTA), DBMath.round(hyb-lyb+2* DRC.TINYDELTA)); // Looking for two corners not inside bounding boxes A and B if (pd == 0) // flat bounding box { pt1 = lowB; pt2 = highB; pt1d = lowB; pt2d = highB; } else { Point2D[] points = rebuild.getPoints(); int[] cornerPoints = new int[2]; int corners = 0; // if more than 3 corners are found -> bounding box is flat for (int i = 0; i < points.length && corners < 2; i++) { if (!DBMath.pointInsideRect(points[i], poly1.getBounds2D()) && !DBMath.pointInsideRect(points[i], poly2.getBounds2D())) { cornerPoints[corners++] = i; } } if (corners != 2) throw new Error("Wrong corners in Quick.foundSmallSizeDefect()"); pt1 = points[cornerPoints[0]]; pt2 = points[cornerPoints[1]]; double delta = ((pt2.getY() - pt1.getY())/(pt2.getX() - pt1.getX()) > 0) ? 1 : -1; // getting point lightly out of the elements if (pt1.getX() < pt2.getX()) { // (y2-y1)/(x2-x1)(x1-tinydelta-x1) + y1 pt1d = new Point2D.Double(pt1.getX()- DRC.TINYDELTA, -delta* DRC.TINYDELTA+pt1.getY()); // (y2-y1)/(x2-x1)(x2+tinydelta-x2) + y2 pt2d = new Point2D.Double(pt2.getX()+ DRC.TINYDELTA, delta* DRC.TINYDELTA+pt2.getY()); } else { pt1d = new Point2D.Double(pt2.getX()- DRC.TINYDELTA, -delta* DRC.TINYDELTA+pt2.getY()); pt2d = new Point2D.Double(pt1.getX()+ DRC.TINYDELTA, delta* DRC.TINYDELTA+pt1.getY()); } if (DBMath.areEquals(pt1.getX(), pt2.getX()) || DBMath.areEquals(pt1.getY(), pt2.getY())) { return false; } } // looking if points around the overlapping area are inside another region // to avoid the error Layer.Function.Set set = Layer.getMultiLayersSet(layer1); DRC.lookForLayerCoverage(geom1, poly1, geom2, poly2, cell, layer1, DBMath.MATID, search, pt1d, pt2d, null, pointsFound, false, set, false, reportInfo.ignoreCenterCuts); // Nothing found if (!pointsFound[0] && !pointsFound[1]) { foundError = true; } return (foundError); } /** * Method to compare: * polygon "poly1" layer "layer1" network "net1" object "geom1" * with: * polygon "poly2" layer "layer2" network "net2" object "geom2" * The polygons are both in technology "tech" and are in the space of cell "cell" * which has global index "globalIndex". * Note that to transform object "geom1" to this space, use "trans1" and to transform * object "geom2" to this space, use "trans2". * They are connected if "con" is nonzero. * They cannot be less than "dist" apart (if "edge" is nonzero, check edges only) * and the rule for this is "rule". * * Returns TRUE if an error has been found. */ private boolean checkDist(Technology tech, Cell cell, int globalIndex, Poly poly1, Layer layer1, int net1, Geometric geom1, FixpTransform trans1, int globalIndex1, Poly poly2, Layer layer2, int net2, Geometric geom2, FixpTransform trans2, int globalIndex2, boolean con, DRCTemplate theRule, boolean edge) { // turn off flag that the nodeinst may be undersized tinyNodeInst = null; Poly origPoly1 = poly1; Poly origPoly2 = poly2; Rectangle2D isBox1 = poly1.getBox(); Rectangle2D trueBox1 = isBox1; if (trueBox1 == null) trueBox1 = poly1.getBounds2D(); Rectangle2D isBox2 = poly2.getBox(); Rectangle2D trueBox2 = isBox2; if (trueBox2 == null) trueBox2 = poly2.getBounds2D(); boolean errorFound = false; // remember if there was a min defect error boolean maytouch = DRC.mayTouch(tech, con, layer1, layer2); // special code if both polygons are manhattan double pd = 0; boolean overlap = false; if (isBox1 != null && isBox2 != null) { // manhattan double pdx = DBMath.round(Math.max(trueBox2.getMinX()-trueBox1.getMaxX(), trueBox1.getMinX()-trueBox2.getMaxX())); double pdy = DBMath.round(Math.max(trueBox2.getMinY()-trueBox1.getMaxY(), trueBox1.getMinY()-trueBox2.getMaxY())); pd = Math.max(pdx, pdy); if (DBMath.areEquals(pdx, 0) && DBMath.areEquals(pdy,0)) pd = 0; // touching overlap = DBMath.isLessThan(pd, 0); if (maytouch) { // they are electrically connected: see if they touch if (checkMinDefects(cell, maytouch, geom1, poly1, trueBox1, layer2, geom2, poly2, trueBox2, layer2, cell)) { if (reportInfo.errorTypeSearch != DRC.DRCCheckMode.ERROR_CHECK_EXHAUSTIVE) return true; errorFound = true; } } // crop out parts of any arc that is covered by an adjoining node trueBox1 = new Rectangle2D.Double(trueBox1.getMinX(), trueBox1.getMinY(), trueBox1.getWidth(), trueBox1.getHeight()); trueBox2 = new Rectangle2D.Double(trueBox2.getMinX(), trueBox2.getMinY(), trueBox2.getWidth(), trueBox2.getHeight()); // first to crop arcs since node cropping crops arcs too! boolean geom1IsNode = (geom1 instanceof NodeInst); boolean geom2IsNode = (geom2 instanceof NodeInst); if (!geom1IsNode) // arc -> crop it first { if (cropArcInst((ArcInst)geom1, layer1, trans1, trueBox1, overlap)) return errorFound; } if (!geom2IsNode) { if (cropArcInst((ArcInst)geom2, layer2, trans2, trueBox2, overlap)) return errorFound; } if (geom1IsNode) { if (cropNodeInst((NodeInst)geom1, globalIndex1, trans1, layer2, net2, geom2, trueBox2)) return errorFound; // } else // { // if (cropArcInst((ArcInst)geom1, layer1, trans1, trueBox1, overlap)) // return errorFound; } if (geom2 instanceof NodeInst) { if (cropNodeInst((NodeInst)geom2, globalIndex2, trans2, layer1, net1, geom1, trueBox1)) return errorFound; // } else // { // if (cropArcInst((ArcInst)geom2, layer2, trans2, trueBox2, overlap)) // return errorFound; } poly1 = new Poly(trueBox1); poly1.setStyle(Poly.Type.FILLED); poly2 = new Poly(trueBox2); poly2.setStyle(Poly.Type.FILLED); // compute the distance double lX1 = trueBox1.getMinX(); double hX1 = trueBox1.getMaxX(); double lY1 = trueBox1.getMinY(); double hY1 = trueBox1.getMaxY(); double lX2 = trueBox2.getMinX(); double hX2 = trueBox2.getMaxX(); double lY2 = trueBox2.getMinY(); double hY2 = trueBox2.getMaxY(); if (edge) { // calculate the spacing between the box edges double pdedge = DBMath.round(Math.min( Math.min(Math.min(Math.abs(lX1-lX2), Math.abs(lX1-hX2)), Math.min(Math.abs(hX1-lX2), Math.abs(hX1-hX2))), Math.min(Math.min(Math.abs(lY1-lY2), Math.abs(lY1-hY2)), Math.min(Math.abs(hY1-lY2), Math.abs(hY1-hY2))))); pd = Math.max(pd, pdedge); } else { pdx = DBMath.round(Math.max(lX2-hX1, lX1-hX2)); pdy = DBMath.round(Math.max(lY2-hY1, lY1-hY2)); if (DBMath.areEquals(pdx, 0) && DBMath.areEquals(pdy, 0)) pd = 0; // they are touching!! else { // They are overlapping if pdx < 0 && pdy < 0 pd = (Math.max(pdx, pdy)); if (pd < theRule.getValue(0) && DBMath.isGreaterThan(pd, 0)) { pd = poly1.separation(poly2); } } } } else { // nonmanhattan Poly.Type style = poly1.getStyle(); if (style != Poly.Type.FILLED && style != Poly.Type.CLOSED && style != Poly.Type.CROSSED && style != Poly.Type.OPENED && style != Poly.Type.OPENEDT1 && style != Poly.Type.OPENEDT2 && style != Poly.Type.OPENEDT3 && style != Poly.Type.VECTORS) return errorFound; style = poly2.getStyle(); if (style != Poly.Type.FILLED && style != Poly.Type.CLOSED && style != Poly.Type.CROSSED && style != Poly.Type.OPENED && style != Poly.Type.OPENEDT1 && style != Poly.Type.OPENEDT2 && style != Poly.Type.OPENEDT3 && style != Poly.Type.VECTORS) return errorFound; // make sure polygons don't intersect //@TODO combine this calculation otherwise Poly.intersects is called twice! double pd1 = poly1.separation(poly2); if (poly1.intersects(poly2)) pd = 0; else { // find distance between polygons pd = poly1.separation(poly2); } // if (pd1 != pd) if (!DBMath.areEquals(pd1, pd)) System.out.println("Wrong case in non-nonmanhattan, Quick."); } DRC.DRCErrorType errorType = DRC.DRCErrorType.SPACINGERROR; if (theRule.ruleType == DRCTemplate.DRCRuleType.SURROUND) { if (DBMath.isGreaterThan(pd, 0)) // layers don't overlap -> no condition to check return errorFound; pd = Math.abs(pd); errorType = DRC.DRCErrorType.SURROUNDERROR; } // see if the design rule is met if (!DBMath.isGreaterThan(theRule.getValue(0), pd)) // default case: SPACING pd >= theRule.value1 { return errorFound; } if (theRule.ruleType != DRCTemplate.DRCRuleType.SURROUND) { /* * special case: ignore errors between two active layers connected * to either side of a field-effect transistor that is inside of * the error area. */ if (activeOnTransistor(poly1, layer1, net1, poly2, layer2, net2, cell, globalIndex)) return errorFound; /** * Special case: ignore spacing errors generated by VT layers if poly is already * part of a VTH-transistors. Not very elegant solution but should work for now. */ if (polyCoverByAnyVTLayer(cell, theRule, tech, new Poly[]{poly1, poly2}, new Layer[]{layer1, layer2}, new Geometric[]{geom1, geom2}, reportInfo.ignoreCenterCuts)) return errorFound; // special cases if the layers are the same if (tech.sameLayer(layer1, layer2)) { // special case: check for "notch" if (maytouch) { // if they touch, it is acceptable if (DBMath.isLessThanOrEqualTo(pd, 0)) return errorFound; // see if the notch is filled boolean newR = lookForCrossPolygons(geom1, poly1, geom2, poly2, layer1, cell, overlap); // if (Job.LOCALDEBUGFLAG) // { // Point2D pt1 = new Point2D.Double(); // Point2D pt2 = new Point2D.Double(); // int intervening = findInterveningPoints(poly1, poly2, pt1, pt2, false); // if (intervening == 0) // { // if (!newR) // { // System.out.println("DIfferent"); // lookForCrossPolygons(geom1, poly1, geom2, poly2, layer1, cell, overlap); // // } // //return false; // } // boolean needBoth = true; // if (intervening == 1) needBoth = false; // // if (lookForPoints(pt1, pt2, layer1, cell, needBoth)) // { // if (!newR) // { // System.out.println("DIfferent"); // lookForPoints(pt1, pt2, layer1, cell, needBoth); // lookForCrossPolygons(geom1, poly1, geom2, poly2, layer1, cell, overlap); // //return false; // } // } // // boolean oldR = lookForPoints(pt1, pt2, layer1, cell, needBoth); // if (oldR != newR) // System.out.println("DIfferent 2"); // } if (newR) return errorFound; // look further if on the same net and diagonally separate (1 intervening point) //if (net1 == net2 && intervening == 1) return false; errorType = DRC.DRCErrorType.NOTCHERROR; } } } String msg = null; if (tinyNodeInst != null) { // see if the node/arc that failed was involved in the error if ((tinyNodeInst == geom1 || tinyNodeInst == geom2) && (tinyGeometric == geom1 || tinyGeometric == geom2)) { msg = tinyNodeInst + " is too small for the " + tinyGeometric; } } DRC.createDRCErrorLogger(reportInfo, errorType, msg, cell, theRule.getValue(0), pd, theRule.ruleName, origPoly1, geom1, layer1, origPoly2, geom2, layer2); return true; } /*************************** QUICK DRC SEE IF GEOMETRICS CAUSE ERRORS ***************************/ /** * Method to examine, in cell "cell", the "count" instances in "geomsToCheck". * If they are DRC clean, set the associated entry in "validity" to TRUE. */ private void checkTheseGeometrics(Cell cell, int count, Geometric [] geomsToCheck, boolean [] validity) { CheckProto cp = getCheckProto(cell); // loop through all of the objects to be checked for(int i=0; i it = cell.searchIterator(searchBounds); it.hasNext(); ) { Geometric geom = it.next(); if ( geom == ni ) continue; if (geom instanceof ArcInst) { if (checkGeomAgainstInstance(netlist, geom, ni)) return true; continue; } NodeInst oNi = (NodeInst)geom; if (oNi.getProto() instanceof PrimitiveNode) { // found a primitive node: check it against the instance contents if (checkGeomAgainstInstance(netlist, geom, ni)) return true; continue; } // found other instance "oNi", look for everything in "ni" that is near it Rectangle2D subNodeBounds = oNi.getBounds(); // double worstInteractionDistanceLocal = cellLayersCon.getWorstSpacingDistance(oNi.getProto()); if (!cellLayersCon.getWorstSpacingDistance(oNi.getProto(), mutableDist)) { System.out.println("No worst spacing distance found in Quick:checkThisCellPlease"); continue; } double worstInteractionDistanceLocal = mutableDist.doubleValue(); Rectangle2D subBounds = new Rectangle2D.Double( subNodeBounds.getMinX() - worstInteractionDistanceLocal, subNodeBounds.getMinY() - worstInteractionDistanceLocal, subNodeBounds.getWidth() + worstInteractionDistanceLocal*2, subNodeBounds.getHeight() + worstInteractionDistanceLocal*2); // recursively search instance "ni" in the vicinity of "oNi" if (checkCellInstContents(subBounds, ni, upTrans, localIndex, oNi, null, globalIndex, null)) return true; } return false; } /** * Method to check primitive object "geom" (an arcinst or primitive nodeinst) against cell instance "ni". * Returns TRUE if there are design-rule violations in their interaction. */ private boolean checkGeomAgainstInstance(Netlist netlist, Geometric geom, NodeInst ni) { NodeProto np = ni.getProto(); int globalIndex = 0; Cell subCell = geom.getParent(); // boolean baseMulti = false; Technology.MultiCutData multiCutData = null; Technology tech = null; Poly [] nodeInstPolyList = null; FixpTransform trans = DBMath.MATID; if (geom instanceof NodeInst) { // get all of the polygons on this node NodeInst oNi = (NodeInst)geom; if (NodeInst.isSpecialNode(oNi)) return false; // Nov 16, no need for checking pins or other special nodes; tech = oNi.getProto().getTechnology(); trans = oNi.rotateOut(); nodeInstPolyList = DRC.getShapeOfNodeBasedOnRules(tech, reportInfo, oNi); convertPseudoLayers(oNi, nodeInstPolyList); multiCutData = tech.getMultiCutData(oNi); // baseMulti = tech.isMultiCutCase(oNi); } else { ArcInst oAi = (ArcInst)geom; tech = oAi.getProto().getTechnology(); nodeInstPolyList = tech.getShapeOfArc(oAi); // nodeInstPolyList = DRC.getShapeOfArcBasedOnRules(tech, oAi); } if (nodeInstPolyList == null) return false; int tot = nodeInstPolyList.length; CheckInst ci = checkInsts.get(ni); if (ci == null) return false; int localIndex = globalIndex * ci.multiplier + ci.localIndex + ci.offset; // examine the polygons on this node MutableDouble mutableDist = new MutableDouble(0); for(int j=0; j nIt = cell.getNodes(); nIt.hasNext(); ) { NodeInst ni = nIt.next(); if (!ni.isCellInstance()) continue; // ignore documentation icons if (ni.isIconOfParent()) continue; Cell subCell = (Cell)ni.getProto(); CheckInst ci = new CheckInst(); checkInsts.put(ni, ci); CheckProto subCP = checkEnumerateProtos(subCell, netlist.getNetlist(ni)); } return cp; } /** * Method to return CheckProto of a Cell. * @param cell Cell to get its CheckProto. * @return CheckProto of a Cell. */ private final CheckProto getCheckProto(Cell cell) { return checkProtos.get(cell); } /** * Method to recursively examine the hierarchy below cell "cell" and fill in the * CheckInst objects on every cell instance. Uses the CheckProto objects * to keep track of cell usage. */ private void checkEnumerateInstances(Cell cell) { if (job != null && job.checkAbort()) return; // number all of the instances in this cell reportInfo.checkTimeStamp++; List subCheckProtos = new ArrayList(); for(Iterator it = cell.getNodes(); it.hasNext(); ) { NodeInst ni = it.next(); NodeProto np = ni.getProto(); if (!ni.isCellInstance()) continue; // ignore documentation icons if (ni.isIconOfParent()) continue; CheckProto cp = getCheckProto((Cell)np); if (cp.timeStamp != reportInfo.checkTimeStamp) { cp.timeStamp = reportInfo.checkTimeStamp; cp.instanceCount = 0; cp.nodesInCell = new ArrayList(); subCheckProtos.add(cp); } CheckInst ci = checkInsts.get(ni); ci.localIndex = cp.instanceCount++; cp.nodesInCell.add(ci); } // update the counts for this cell for (CheckProto cp : subCheckProtos) { cp.hierInstanceCount += cp.instanceCount; for (CheckInst ci : cp.nodesInCell) { ci.multiplier = cp.instanceCount; } } // now recurse for(Iterator it = cell.getNodes(); it.hasNext(); ) { NodeInst ni = it.next(); NodeProto np = ni.getProto(); if (!ni.isCellInstance()) continue; // ignore documentation icons if (ni.isIconOfParent()) continue; checkEnumerateInstances((Cell)np); } } private void checkEnumerateNetworks(Cell cell, CheckProto cp, int globalIndex, HashMap enumeratedNets) { // store all network information in the appropriate place for(Iterator nIt = cp.netlist.getNetworks(); nIt.hasNext(); ) { Network net = nIt.next(); Integer netNumber = enumeratedNets.get(net); Integer [] netNumbers = networkLists.get(net); netNumbers[globalIndex] = netNumber; } for(Iterator it = cell.getNodes(); it.hasNext(); ) { NodeInst ni = it.next(); NodeProto np = ni.getProto(); if (!ni.isCellInstance()) continue; // ignore documentation icons if (ni.isIconOfParent()) continue; // compute the index of this instance CheckInst ci = checkInsts.get(ni); int localIndex = globalIndex * ci.multiplier + ci.localIndex + ci.offset; // propagate down the hierarchy Cell subCell = (Cell)np; CheckProto subCP = getCheckProto(subCell); HashMap subEnumeratedNets = new HashMap(); for(Iterator pIt = ni.getPortInsts(); pIt.hasNext(); ) { PortInst pi = pIt.next(); Export subPP = (Export)pi.getPortProto(); Network net = cp.netlist.getNetwork(ni, subPP, 0); if (net == null) continue; Integer netNumber = enumeratedNets.get(net); Network subNet = subCP.netlist.getNetwork(subPP, 0); subEnumeratedNets.put(subNet, netNumber); } for(Iterator nIt = subCP.netlist.getNetworks(); nIt.hasNext(); ) { Network net = nIt.next(); if (subEnumeratedNets.get(net) == null) subEnumeratedNets.put(net, new Integer(reportInfo.checkNetNumber++)); } checkEnumerateNetworks(subCell, subCP, localIndex, subEnumeratedNets); } } /*********************************** QUICK DRC SUPPORT ***********************************/ /** * Function to look for conditional layers that will 100% overlap with the given region. * @param poly * @param layer * @param cell * @param ignoreCenterCuts * @return true if conditional layers are found for the test points */ private boolean searchForCondLayer(Geometric geom, Poly poly, Layer layer, Cell cell, boolean ignoreCenterCuts) { Rectangle2D polyBnd = poly.getBounds2D(); double midPointX = (polyBnd.getMinX() + polyBnd.getMaxX())/2; double midPointY = (polyBnd.getMinY()+polyBnd.getMaxY())/2; Point2D pt1 = new Point2D.Double(midPointX, polyBnd.getMinY()); Point2D pt2 = new Point2D.Double(midPointX, polyBnd.getMaxY()); Point2D pt3 = new Point2D.Double(midPointX, midPointY); // compute bounds for searching inside the given polygon Rectangle2D bnd = new Rectangle2D.Double(DBMath.round(polyBnd.getMinX()- DRC.TINYDELTA), DBMath.round(polyBnd.getMinY()- DRC.TINYDELTA), DBMath.round(polyBnd.getWidth()+2* DRC.TINYDELTA), DBMath.round(polyBnd.getHeight()+2* DRC.TINYDELTA)); // looking if points around the overlapping area are inside another region // to avoid the error boolean [] pointsFound = new boolean[3]; pointsFound[0] = pointsFound[1] = pointsFound[2] = false; Layer.Function.Set set = Layer.getMultiLayersSet(layer); // Test first with a vertical line boolean found = DRC.lookForLayerCoverage(geom, poly, null, null, cell, layer, DBMath.MATID, bnd, pt1, pt2, pt3, pointsFound, true, set, false, ignoreCenterCuts); if (!found) return found; // no need of checking horizontal line if the vertical test was not positive pt1.setLocation(polyBnd.getMinX(), midPointY); pt2.setLocation(polyBnd.getMaxX(), midPointY); pointsFound[0] = pointsFound[1] = false; pointsFound[2] = true; // no testing pt3 again found = DRC.lookForLayerCoverage(geom, poly, null, null, cell, layer, DBMath.MATID, bnd, pt1, pt2, null, pointsFound, true, set, false, ignoreCenterCuts); return found; } /** * Method to ensure that polygon "poly" on layer "layer" from object "geom" in * technology "tech" meets minimum width rules. If it is too narrow, other layers * in the vicinity are checked to be sure it is indeed an error. Returns true * if an error is found. */ private boolean checkMinWidth(Geometric geom, Layer layer, Poly poly, boolean onlyOne) { DRCTemplate minWidthRule = DRC.getMinValue(layer, DRCTemplate.DRCRuleType.MINWID); Layer.Function.Set set = Layer.getMultiLayersSet(layer); boolean errorDefault = false; // Only if there is one default size if (minWidthRule != null) { errorDefault = DRC.checkMinWidthInternal(geom, layer, poly, onlyOne, minWidthRule, false, set, reportInfo); if (!errorDefault) return false; // the default condition is the valid one. } DRCTemplate minWidthRuleCond = DRC.getMinValue(layer, DRCTemplate.DRCRuleType.MINWIDCOND); // No appropiate overlapping condition if (minWidthRuleCond == null || !minWidthRuleCond.condition.startsWith("overlap(")) { // Now the error is reporte. Not very efficient if (errorDefault) DRC.checkMinWidthInternal(geom, layer, poly, onlyOne, minWidthRule, true, set, reportInfo); return errorDefault; } // checking if geometry complains with overlap condition // Skipping "overlap" String[] layers = TextUtils.parseString(minWidthRuleCond.condition.substring(7), "(,)"); boolean found = false; for (String la : layers) { Layer l = layer.getTechnology().findLayer(la); found = searchForCondLayer(geom, poly, l, geom.getParent(), reportInfo.ignoreCenterCuts); if (!found) break; // no need to check the next layer } // If condition is met then the new rule applied. if (found) errorDefault = DRC.checkMinWidthInternal(geom, layer, poly, onlyOne, minWidthRuleCond, true, set, reportInfo); else if (errorDefault) // report the errors here in case of default values DRC.checkMinWidthInternal(geom, layer, poly, onlyOne, minWidthRule, true, set, reportInfo); return errorDefault; } // private int checkMinAreaLayer(GeometryHandler merge, Cell cell, Layer layer, boolean addError, // HashMap minAreaLayerMapDone, HashMap enclosedAreaLayerMapDone) // { // int errorFound = 0; // DRCTemplate minAreaRule = minAreaLayerMap.get(layer); // DRCTemplate encloseAreaRule = enclosedAreaLayerMap.get(layer); // DRCTemplate slotSizeRule = slotSizeLayerMap.get(layer); // // // Layer doesn't have min area nor slot size // if (minAreaRule == null && encloseAreaRule == null && slotSizeRule == null) return 0; // // Collection set = merge.getObjects(layer, false, true); // // if (set == null) return 0; // layer is not present in this cell // // boolean minAreaDone = true; // boolean enclosedAreaDone = true; // // for (PolyBase obj : set) // { // if (obj == null) throw new Error("wrong condition in Quick.checkMinArea()"); // // List list = obj.getSortedLoops(); // // // Order depends on area comparison done. First element is the smallest. // // and depending on # polygons it could be minArea or encloseArea // DRCTemplate evenRule = (list.size()%2==0) ? encloseAreaRule : minAreaRule; // DRCTemplate oddRule = (evenRule == minAreaRule) ? encloseAreaRule : minAreaRule; // // Looping over simple polygons. Possible problems with disconnected elements // // polyArray.length = Maximum number of distintic loops // int i = 0; // for (PolyBase listObj : list) // { // double area = listObj.getArea(); // DRCTemplate minRule = (i%2 == 0) ? evenRule : oddRule; // PolyBase simplePn = listObj; // i++; // // // Check slot size when area is checked // if (minRule == minAreaRule && slotSizeRule != null) // { // double length = listObj.getMaxLength(); // // if (!DBMath.isGreaterThan(length, slotSizeRule.getValue(0))) continue; // if (addError) // reportError(DRC.DRCErrorType.SLOTSIZEERROR, null, cell, slotSizeRule.getValue(0), length, slotSizeRule.ruleName, // simplePn, null, layer, null, null, null); // errorFound++; // } // // if (minRule == null) continue; // // // isGreaterThan doesn't consider equals condition therefore negate condition is used // if (!DBMath.isGreaterThan(minRule.getValue(0), area)) continue; // // errorFound++; // DRC.DRCErrorType errorType = (minRule == minAreaRule) ? DRC.DRCErrorType.MINAREAERROR : DRC.DRCErrorType.ENCLOSEDAREAERROR; // if (errorType == DRC.DRCErrorType.MINAREAERROR) minAreaDone = false; // else if (errorType == DRC.DRCErrorType.ENCLOSEDAREAERROR) enclosedAreaDone = false; // if (addError) // reportError(errorType, null, cell, minRule.getValue(0), area, minRule.ruleName, // simplePn, null, layer, null, null, null); // } // } // if (minAreaDone && minAreaLayerMapDone != null) // minAreaLayerMapDone.put(layer, layer); // if (enclosedAreaDone && enclosedAreaLayerMapDone != null) // enclosedAreaLayerMapDone.put(layer, layer); // return errorFound; // // } private void traversePolyTree(Layer layer, PolyBase.PolyBaseTree obj, int level, DRCTemplate minAreaRule, DRCTemplate encloseAreaRule, DRCTemplate spacingRule, Cell cell, MutableInteger count) { for (PolyBase.PolyBaseTree son : obj.getSons()) { traversePolyTree(layer, son, level+1, minAreaRule, encloseAreaRule, spacingRule, cell, count); } boolean minAreaCheck = level%2 == 0; boolean checkMin = false, checkNotch = false; DRC.DRCErrorType errorType = DRC.DRCErrorType.MINAREAERROR; double minVal = 0; String ruleName = ""; if (minAreaCheck) { if (minAreaRule == null) return; // no rule minVal = minAreaRule.getValue(0); ruleName = minAreaRule.ruleName; checkMin = true; } else { // odd level checks enclose area and holes (spacing rule) errorType = DRC.DRCErrorType.ENCLOSEDAREAERROR; if (encloseAreaRule != null) { minVal = encloseAreaRule.getValue(0); ruleName = encloseAreaRule.ruleName; checkMin = true; } checkNotch = (spacingRule != null); } PolyBase poly = obj.getPoly(); if (checkMin) { double area = poly.getArea(); // isGreaterThan doesn't consider equals condition therefore negate condition is used if (!DBMath.isGreaterThan(minVal, area)) return; // larger than the min value count.increment(); DRC.createDRCErrorLogger(reportInfo, errorType, null, cell, minVal, area, ruleName, poly, null, layer, null, null, null); } if (checkNotch) { // Notches are calculated using the bounding box of the polygon -> this is an approximation Rectangle2D bnd = poly.getBounds2D(); if (bnd.getWidth() < spacingRule.getValue(0)) { count.increment(); DRC.createDRCErrorLogger(reportInfo, DRC.DRCErrorType.NOTCHERROR, "(X axis)", cell, spacingRule.getValue(0), bnd.getWidth(), spacingRule.ruleName, poly, null, layer, null, null, layer); } if (bnd.getHeight() < spacingRule.getValue(1)) { count.increment(); DRC.createDRCErrorLogger(reportInfo, DRC.DRCErrorType.NOTCHERROR, "(Y axis)", cell, spacingRule.getValue(1), bnd.getHeight(), spacingRule.ruleName, poly, null, layer, null, null, layer); } } } private int checkMinAreaLayerWithTree(LayoutMerger merge, Cell cell, Layer layer) { DRCTemplate minAreaRule = minAreaLayerMap.get(layer); DRCTemplate encloseAreaRule = enclosedAreaLayerMap.get(layer); DRCTemplate spacingRule = spacingLayerMap.get(layer); // Layer doesn't have min areae if (minAreaRule == null && encloseAreaRule == null && spacingRule == null) return 0; MutableInteger errorFound = new MutableInteger(0); for (PolyBase.PolyBaseTree obj : merge.merge(layer)) { traversePolyTree(layer, obj, 0, minAreaRule, encloseAreaRule, spacingRule, cell, errorFound); } return errorFound.intValue(); } private int checkMinAreaSlow(Cell cell) { // Nothing to check if (minAreaLayerMap.isEmpty() && enclosedAreaLayerMap.isEmpty() && spacingLayerMap.isEmpty()) return 0; // remember number of errors before the min area checking int errorFound = reportInfo.errorLogger.getNumErrors(); // Get merged areas. DRC.DRCCheckMinArea algoType = dp.minAreaAlgoOption; HierarchyEnumerator.Visitor quickArea = null; switch(algoType) { case AREA_BASIC: quickArea = new QuickAreaEnumeratorSlow(mergeMode); break; case AREA_LOCAL: quickArea = new QuickAreaEnumeratorLocal(mergeMode); break; case AREA_MANHATTAN: quickArea = new QuickAreaEnumeratorManhattan(); break; } HierarchyEnumerator.enumerateCell(cell, VarContext.globalContext, quickArea); errorFound = reportInfo.errorLogger.getNumErrors() - errorFound; return errorFound; } /** * Method to ensure that polygon "poly" on layer "layer" from object "geom" in * technology "tech" meets minimum area rules. Returns true * if an error is found. */ // private int checkMinArea(Cell cell) // { // CheckProto cp = getCheckProto(cell); // int errorFound = 0; // // // Nothing to check // if (minAreaLayerMap.isEmpty() && enclosedAreaLayerMap.isEmpty() && spacingLayerMap.isEmpty()) // return 0; // // // Select/well regions // GeometryHandler selectMerge = GeometryHandler.createGeometryHandler(mergeMode, 0); // HashMap notExportedNodes = new HashMap(); // HashMap checkedNodes = new HashMap(); // // // remember number of errors before the min area checking // errorFound = errorLogger.getNumErrors(); // // // Get merged areas. Only valid for layers that have connections (metals/polys). No valid for NP/PP rule // QuickAreaEnumerator quickArea = new QuickAreaEnumerator(cp.netlist, selectMerge, notExportedNodes, checkedNodes, // mergeMode); // quickArea.setPreProcessFlag(false); // HierarchyEnumerator.enumerateCell(cell, VarContext.globalContext, quickArea); // // // Job aborted // if (job != null && job.checkAbort()) return 0; // // errorFound = errorLogger.getNumErrors() - errorFound; // // // Checking nodes not exported down in the hierarchy. Probably good enough not to collect networks first // // Maybe it would be better to check notExportNodes with respect to local cells. No need of checking // // the entire hierarchy again! // quickArea = new QuickAreaEnumerator(selectMerge, notExportedNodes, checkedNodes, mergeMode); // HierarchyEnumerator.enumerateCell(cell, VarContext.globalContext, quickArea); // // Non exported nodes //// for(Iterator it = quickArea.mainMerge.getKeyIterator(); it.hasNext(); ) //// { //// Layer layer = (Layer)it.next(); //// boolean localError = checkMinAreaLayer(quickArea.mainMerge, cell, layer); //// if (!errorFound) errorFound = localError; //// } // selectMerge.postProcess(true); // // // Special cases for select areas. You can't evaluate based on networks // for (Layer layer : selectMerge.getKeySet()) // { //// errorFound += checkMinAreaLayer(selectMerge, cell, layer, true, null, null); // errorFound += checkMinAreaLayerWithTree(selectMerge, cell, layer, true, null, null); // } // // return errorFound; // } // private int checkMinAreaAgain(Cell cell) // { // CheckProto cp = getCheckProto(cell); // int errorFound = 0; // // // Nothing to check // if (minAreaLayerMap.isEmpty() && enclosedAreaLayerMap.isEmpty()) // return 0; // // // Select/well regions // GeometryHandler selectMerge = GeometryHandler.createGeometryHandler(mergeMode, 0); //new PolyQTree(cell.getBounds()); // HashMap notExportedNodes = new HashMap(); // HashMap checkedNodes = new HashMap(); // // // remember number of errors before the min area checking // errorFound = errorLogger.getNumErrors(); // // // Get merged areas. Only valid for layers that have connections (metals/polys). No valid for NP/PP rule // QuickAreaEnumeratorAgain quickArea = new QuickAreaEnumeratorAgain(cp.netlist, selectMerge, notExportedNodes, checkedNodes, // mergeMode); // quickArea.setPreProcessFlag(false); // HierarchyEnumerator.enumerateCell(cell, VarContext.globalContext, quickArea); // // // Job aborted // if (job != null && job.checkAbort()) return 0; // // errorFound = errorLogger.getNumErrors() - errorFound; // // // Checking nodes not exported down in the hierarchy. Probably good enough not to collect networks first // // Maybe it would be better to check notExportNodes with respect to local cells. No need of checking // // the entire hierarchy again! // quickArea = new // (selectMerge, notExportedNodes, checkedNodes, mergeMode); // HierarchyEnumerator.enumerateCell(cell, VarContext.globalContext, quickArea); // selectMerge.postProcess(true); // // // Special cases for select areas. You can't evaluate based on networks // for (Layer layer : selectMerge.getKeySet()) // { // errorFound += checkMinAreaLayer(selectMerge, cell, layer, true, null, null); // } // // return errorFound; // } /** * Method to find two points between polygons "poly1" and "poly2" that can be used to test * for notches. The points are returned in (xf1,yf1) and (xf2,yf2). Returns zero if no * points exist in the gap between the polygons (becuase they don't have common facing edges). * Returns 1 if only one of the reported points needs to be filled (because the polygons meet * at a point). Returns 2 if both reported points need to be filled. */ private int findInterveningPoints(Poly poly1, Poly poly2, Point2D pt1, Point2D pt2, boolean newFix) { Rectangle2D isBox1 = poly1.getBox(); Rectangle2D isBox2 = poly2.getBox(); // Better to treat serpentine cases with bouding box if (newFix) { if (isBox1 == null) isBox1 = poly1.getBounds2D(); if (isBox2 == null) isBox2 = poly2.getBounds2D(); } if (isBox1 != null && isBox2 != null) { // handle vertical gap between polygons if (isBox1.getMinX() > isBox2.getMaxX() || isBox2.getMinX() > isBox1.getMaxX()) { // see if the polygons are horizontally aligned if (isBox1.getMinY() <= isBox2.getMaxY() && isBox2.getMinY() <= isBox1.getMaxY()) { double yf1 = Math.max(isBox1.getMinY(), isBox2.getMinY()); double yf2 = Math.min(isBox1.getMaxY(), isBox2.getMaxY()); if (isBox1.getMinX() > isBox2.getMaxX()) { double x = (isBox1.getMinX() + isBox2.getMaxX()) / 2; pt1.setLocation(x, yf1); pt2.setLocation(x, yf2); } else { double x = (isBox2.getMinX() + isBox1.getMaxX()) / 2; pt1.setLocation(x, yf1); pt2.setLocation(x, yf2); } return 2; } } else if (isBox1.getMinY() > isBox2.getMaxY() || isBox2.getMinY() > isBox1.getMaxY()) { // see if the polygons are horizontally aligned if (isBox1.getMinX() <= isBox2.getMaxX() && isBox2.getMinX() <= isBox1.getMaxX()) { double xf1 = Math.max(isBox1.getMinX(), isBox2.getMinX()); double xf2 = Math.min(isBox1.getMaxX(), isBox2.getMaxX()); if (isBox1.getMinY() > isBox2.getMaxY()) { double y = (isBox1.getMinY() + isBox2.getMaxY()) / 2; pt1.setLocation(xf1, y); pt2.setLocation(xf2, y); } else { double y = (isBox2.getMinY() + isBox1.getMaxY()) / 2; pt1.setLocation(xf1, y); pt2.setLocation(xf2, y); } return 2; } } else if ((isBox1.getMinX() == isBox2.getMaxX() || isBox2.getMinX() == isBox1.getMaxX()) || (isBox1.getMinY() == isBox2.getMaxY() || isBox2.getMinY() == isBox2.getMaxY())) { // handle touching at a point double xc = isBox2.getMinX(); if (isBox1.getMinX() == isBox2.getMaxX()) xc = isBox1.getMinX(); double yc = isBox2.getMinY(); if (isBox1.getMinY() == isBox2.getMaxY()) yc = isBox1.getMinY(); double xPlus = xc + DRC.TINYDELTA; double yPlus = yc + DRC.TINYDELTA; pt1.setLocation(xPlus, yPlus); pt2.setLocation(xPlus, yPlus); if ((xPlus < isBox1.getMinX() || xPlus > isBox1.getMaxX() || yPlus < isBox1.getMinY() || yPlus > isBox1.getMaxY()) && (xPlus < isBox2.getMinX() || xPlus > isBox2.getMaxX() || yPlus < isBox2.getMinY() || yPlus > isBox2.getMaxY())) return 1; pt1.setLocation(xc + DRC.TINYDELTA, yc - DRC.TINYDELTA); pt2.setLocation(xc - DRC.TINYDELTA, yc + DRC.TINYDELTA); return 1; } // handle manhattan objects that are on a diagonal if (isBox1.getMinX() > isBox2.getMaxX()) { if (isBox1.getMinY() > isBox2.getMaxY()) { pt1.setLocation(isBox1.getMinX(), isBox1.getMinY()); pt2.setLocation(isBox2.getMaxX(), isBox2.getMaxY()); return 1; } if (isBox2.getMinY() > isBox1.getMaxY()) { pt1.setLocation(isBox1.getMinX(), isBox1.getMaxY()); pt2.setLocation(isBox2.getMaxX(), isBox2.getMinY()); return 1; } } if (isBox2.getMinX() > isBox1.getMaxX()) { if (isBox1.getMinY() > isBox2.getMaxY()) { pt1.setLocation(isBox1.getMaxX(), isBox1.getMinY()); pt2.setLocation(isBox2.getMinX(), isBox2.getMaxY()); return 1; } if (isBox2.getMinY() > isBox1.getMaxY()) { pt1.setLocation(isBox1.getMaxX(), isBox1.getMaxY()); pt2.setLocation(isBox2.getMinX(), isBox2.getMinY()); return 1; } } } // boxes don't line up or this is a nonmanhattan situation isBox1 = poly1.getBounds2D(); isBox2 = poly2.getBounds2D(); pt1.setLocation((isBox1.getMinX() + isBox1.getMaxX()) / 2, (isBox2.getMinY() + isBox2.getMaxY()) / 2); pt2.setLocation((isBox2.getMinX() + isBox2.getMaxX()) / 2, (isBox1.getMinY() + isBox1.getMaxY()) / 2); return 1; } /** * Method to explore the points (xf1,yf1) and (xf2,yf2) to see if there is * geometry on layer "layer" (in or below cell "cell"). Returns true if there is. * If "needBoth" is true, both points must have geometry, otherwise only 1 needs it. */ private boolean lookForCrossPolygons(Geometric geo1, Poly poly1, Geometric geo2, Poly poly2, Layer layer, Cell cell, boolean overlap) { Point2D pt1 = new Point2D.Double(); Point2D pt2 = new Point2D.Double(); findInterveningPoints(poly1, poly2, pt1, pt2, true); // compute bounds for searching inside cells double flx = Math.min(pt1.getX(), pt2.getX()); double fhx = Math.max(pt1.getX(), pt2.getX()); double fly = Math.min(pt1.getY(), pt2.getY()); double fhy = Math.max(pt1.getY(), pt2.getY()); Rectangle2D bounds = new Rectangle2D.Double(DBMath.round(flx- DRC.TINYDELTA), DBMath.round(fly- DRC.TINYDELTA), DBMath.round(fhx-flx+2* DRC.TINYDELTA), DBMath.round(fhy-fly+2* DRC.TINYDELTA)); // Adding delta otherwise it won't consider points along edges. // Mind bounding boxes could have zero width or height // search the cell for geometry that fills the notch boolean [] pointsFound = new boolean[2]; pointsFound[0] = pointsFound[1] = false; Layer.Function.Set set = Layer.getMultiLayersSet(layer); boolean allFound = DRC.lookForLayerCoverage(geo1, poly1, geo2, poly2, cell, layer, DBMath.MATID, bounds, pt1, pt2, null, pointsFound, overlap, set, false, reportInfo.ignoreCenterCuts); return allFound; } /** * Method to examine cell "cell" in the area (lx<=X<=hx, ly<=Y<=hy) for objects * on layer "layer". Apply transformation "moreTrans" to the objects. If polygons are * found at (xf1,yf1) or (xf2,yf2) or (xf3,yf3) then sets "p1found/p2found/p3found" to 1. * If all locations are found, returns true. */ private boolean lookForLayerWithPoints(Geometric geo1, Poly poly1, Geometric geo2, Poly poly2, Cell cell, Layer layer, FixpTransform moreTrans, Rectangle2D bounds, Point2D[] pts, boolean[] pointsFound, int length, boolean overlap) { assert (pts.length == pointsFound.length); int j; Rectangle2D newBounds = new Rectangle2D.Double(); // Sept 30 Layer.Function.Set set = Layer.getMultiLayersSet(layer); for(Iterator it = cell.searchIterator(bounds); it.hasNext(); ) { Geometric g = it.next(); // You can't skip the same geometry otherwise layers in the same Geometric won't // be tested. // if (ignoreSameGeometry && (g == geo1 || g == geo2)) // continue; // I can't skip geometries to exclude from the search if (g instanceof NodeInst) { NodeInst ni = (NodeInst)g; if (NodeInst.isSpecialNode(ni)) continue; // Nov 16, no need for checking pins or other special nodes; if (ni.isCellInstance()) { // compute bounding area inside of sub-cell FixpTransform rotI = ni.rotateIn(); FixpTransform transI = ni.translateIn(); rotI.preConcatenate(transI); newBounds.setRect(bounds); DBMath.transformRect(newBounds, rotI); // compute new matrix for sub-cell examination FixpTransform trans = ni.translateOut(ni.rotateOut()); trans.preConcatenate(moreTrans); if (lookForLayerWithPoints(geo1, poly1, geo2, poly2, (Cell)ni.getProto(), layer, trans, newBounds, pts, pointsFound, length, overlap)) return true; continue; } Technology tech = ni.getProto().getTechnology(); // I have to ask for electrical layers otherwise it will retrieve one polygon for polysilicon // and poly.polySame(poly1) will never be true. CONTRADICTION! Poly [] layerLookPolyList = tech.getShapeOfNode(ni, false, reportInfo.ignoreCenterCuts, set); int tot = layerLookPolyList.length; if (tot == 0) continue; FixpTransform bound = ni.rotateOut(); bound.preConcatenate(moreTrans); for(int i=0; i sIt = cell.searchIterator(polyBnd); sIt.hasNext(); ) // { // Geometric g = (Geometric)sIt.next(); // if (g == geom) continue; // if ((g instanceof NodeInst)) // { // NodeInst ni = (NodeInst)g; // NodeProto np = ni.getProto(); // if (NodeInst.isSpecialNode(ni)) continue; // Nov 4; // if (ni.isCellInstance()) // { // AffineTransform cellDownTrans = ni.transformIn(); // AffineTransform cellUpTrans = ni.transformOut(); // DBMath.transformRect(polyBnd, cellDownTrans); // extensionArea.transform(cellDownTrans); // overlapArea.transform(cellDownTrans); // checkExtensionOverlapRule(geom, layer, (Cell)np, baseArea, extensionArea, overlapArea, polyBnd); // DBMath.transformRect(polyBnd, cellUpTrans); // extensionArea.transform(cellUpTrans); // overlapArea.transform(cellUpTrans); // continue; // } // } // // Poly [] primPolyList = getShapeOfGeometric(g, layer); // int tot = primPolyList.length; // for(int j=0; j rules = DRC.getRules(layer, DRCTemplate.DRCRuleType.SURROUND); //A AB B // +----------------------------+ // | | //A| | B //D| | C // | | // | | // +----------------------------+ //D DC C Point2D[] basePts = new Point2D[4]; // boolean[] baseFound = new boolean[4]; // all false at the beginning // NOTE: Enough to find a point matching 1 rule to be OK. Rectangle2D polyBnd = poly.getBounds2D(); basePts[0] = new Point2D.Double(polyBnd.getMinX(), polyBnd.getMinY()); basePts[1] = new Point2D.Double(polyBnd.getMinX(), polyBnd.getMaxY()); basePts[2] = new Point2D.Double(polyBnd.getMaxX(), polyBnd.getMaxY()); basePts[3] = new Point2D.Double(polyBnd.getMaxX(), polyBnd.getMinY()); for (DRCTemplate rule : rules) { if (rule.nodeName != null) continue; // ignore these ones, only use to resize primitives if (rule.condition == null) continue; // must be conditional if (!rule.name1.equals(layer.getName())) continue; // it has to be the first name String[] layersS = TextUtils.parseString(rule.condition.substring(2), "(,)"); // 2 to skip "or" Layer[] layers = new Layer[layersS.length]; for (int i = 0; i < layersS.length; i++) { layers[i] = layer.getTechnology().findLayer(layersS[i]); } for (int j = 0; j < 4; j++) { boolean[] basicFound = new boolean[3]; Point2D[] basicPts = new Point2D[3]; basicFound[0] = false; basicPts[0] = basePts[j]; Rectangle2D basicBnd = new Rectangle2D.Double(DBMath.round(basicPts[0].getX()- DRC.TINYDELTA), DBMath.round(basicPts[0].getY()- DRC.TINYDELTA), 2*(DRC.TINYDELTA), 2*(DRC.TINYDELTA)); boolean f = false; for (int i = 0; i < layers.length; i++) { f = lookForLayerWithPoints(geom, poly, null, null, cell, layers[i], DBMath.MATID, basicBnd, basicPts, basicFound, 1, true); if (f) break; // found } if (!f) continue; // no point in layers found // now testing the rule basicFound[0] = basicFound[1] = basicFound[2] = false; double cos45 = 1.0/Math.sqrt(2); double xValue = rule.getValue(0); // on the diagonal, 45 degrees double yValue = rule.getValue(1); double x45Value = xValue * cos45; // on the diagonal, 45 degrees double y45Value = yValue * cos45; Point2D basicBndPoint = null; // Sample 3 points per vertex to detect corners. switch (j) { case 0: // Diagonal basicPts[0] = new Point2D.Double(polyBnd.getMinX()-x45Value, polyBnd.getMinY()-y45Value); // left basicPts[1] = new Point2D.Double(polyBnd.getMinX()-xValue, polyBnd.getMinY()); // bottom basicPts[2] = new Point2D.Double(polyBnd.getMinX(), polyBnd.getMinY()-yValue); basicBndPoint = new Point2D.Double(polyBnd.getMinX()-xValue, polyBnd.getMinY()-yValue); break; case 1: basicPts[0] = new Point2D.Double(polyBnd.getMinX()-x45Value, polyBnd.getMaxY()+y45Value); basicPts[1] = new Point2D.Double(polyBnd.getMinX()-xValue, polyBnd.getMaxY()); basicPts[2] = new Point2D.Double(polyBnd.getMinX(), polyBnd.getMaxY()+yValue); basicBndPoint = basicPts[1]; break; case 2: basicPts[0] = new Point2D.Double(polyBnd.getMaxX()+x45Value, polyBnd.getMaxY()+y45Value); basicPts[1] = new Point2D.Double(polyBnd.getMaxX()+xValue, polyBnd.getMaxY()); basicPts[2] = new Point2D.Double(polyBnd.getMaxX(), polyBnd.getMaxY()+yValue); basicBndPoint = new Point2D.Double(polyBnd.getMaxX(), polyBnd.getMaxY()); break; case 3: basicPts[0] = new Point2D.Double(polyBnd.getMaxX()+x45Value, polyBnd.getMinY()-y45Value); basicPts[1] = new Point2D.Double(polyBnd.getMaxX()+xValue, polyBnd.getMinY()); basicPts[2] = new Point2D.Double(polyBnd.getMaxX(), polyBnd.getMinY()-yValue); basicBndPoint = basicPts[2]; break; } basicBnd = new Rectangle2D.Double(DBMath.round(basicBndPoint.getX()- DRC.TINYDELTA), DBMath.round(basicBndPoint.getY()- DRC.TINYDELTA), DBMath.round(xValue+2*(DRC.TINYDELTA)), DBMath.round(yValue+2*(DRC.TINYDELTA))); for (int i = 0; i < layers.length; i++) { f = lookForLayerWithPoints(geom, poly, null, null, cell, layers[i], DBMath.MATID, basicBnd, basicPts, basicFound, 3, true); if (f) break; // found } if (!f) { DRC.createDRCErrorLogger(reportInfo, DRC.DRCErrorType.LAYERSURROUNDERROR, "Not enough surround of " + rule.condition + ", ", geom.getParent(), rule.getValue(0), -1, rule.ruleName, poly, geom, layer, null, null, null); if (reportInfo.errorTypeSearch != DRC.DRCCheckMode.ERROR_CHECK_EXHAUSTIVE) return true; // no need of checking other combinations break; // with next rule } } } return false; } /****************************** Select Over Polysilicon Functions ***************************/ /** * Method to check if non-transistor polysilicons are completed covered by N++/P++ regions */ // private boolean checkSelectOverPolysilicon(Geometric geom, Layer layer, Poly poly, Cell cell) // { // if(DRC.isIgnoreExtensionRuleChecking()) return false; // // if (!layer.getFunction().isPoly()) return false; // // One layer must be select and other polysilicon. They are not connected // // DRCTemplate minOverlapRule = DRC.getMinValue(layer, DRCTemplate.DRCRuleType.EXTENSION); // if (minOverlapRule == null) return false; // double minOverlapValue = minOverlapRule.getValue(0); // Rectangle2D polyBnd = poly.getBounds2D(); // Area polyArea = new Area(poly); // boolean found = polyArea.isEmpty(); // List checkExtraPoints = new ArrayList(); // // found = checkThisCellExtensionRule(geom, layer, poly, null, cell, polyArea, polyBnd, minOverlapRule, // found, checkExtraPoints); // // // error if the merged area doesn't contain 100% the search area. // if (!found) // { // List polyList = PolyBase.getPointsInArea(polyArea, layer, true, true, null); // // for (PolyBase nPoly : polyList) // { // reportError(DRCErrorType.LAYERSURROUNDERROR, "Polysilicon not covered, ", cell, minOverlapValue, -1, // minOverlapRule.ruleName, nPoly, geom, layer, null, null, null); // } // } // else // { // // Checking if not enough coverage // Point2D[] extraPoints = new Point2D[checkExtraPoints.size()]; // checkExtraPoints.toArray(extraPoints); // boolean[] founds = new boolean[checkExtraPoints.size()]; // Arrays.fill(founds, false); // Rectangle2D ruleBnd = new Rectangle2D.Double(polyBnd.getMinX()-minOverlapValue, // polyBnd.getMinY()-minOverlapValue, // polyBnd.getWidth() + minOverlapValue*2, // polyBnd.getHeight() + minOverlapValue*2); // boolean foundAll = allPointsContainedInLayer(geom, cell, ruleBnd, null, extraPoints, founds); // // if (!foundAll) // reportError(DRCErrorType.LAYERSURROUNDERROR, "Not enough surround, ", geom.getParent(), minOverlapValue, // -1, minOverlapRule.ruleName, poly, geom, layer, null, null, null); // } // return (!found); // } // private boolean checkThisCellExtensionRule(Geometric geom, Layer layer, Poly poly, Layer.Function.Set drcLayers, Cell cell, Area polyArea, // Rectangle2D polyBnd, DRCTemplate minOverlapRule, boolean found, // List checkExtraPoints) // { // boolean[] founds = new boolean[4]; // // for(Iterator sIt = cell.searchIterator(polyBnd); !found && sIt.hasNext(); ) // { // RTBounds g = sIt.next(); // if (g == geom) continue; // if (!(g instanceof NodeInst)) // { // if (Job.LOCALDEBUGFLAG && !DRC.isIgnoreExtensionRuleChecking()) // System.out.println("Skipping arcs!"); // continue; // Skipping arcs!!!! // } // NodeInst ni = (NodeInst)g; // NodeProto np = ni.getProto(); // if (NodeInst.isSpecialNode(ni)) continue; // Nov 4; // if (ni.isCellInstance()) // { // AffineTransform cellDownTrans = ni.transformIn(); // AffineTransform cellUpTrans = ni.transformOut(); // DBMath.transformRect(polyBnd, cellDownTrans); // polyArea.transform(cellDownTrans); // poly.transform(cellDownTrans); // List newExtraPoints = new ArrayList(); // found = checkThisCellExtensionRule(geom, layer, poly, drcLayers, (Cell)np, polyArea, polyBnd, minOverlapRule, // found, newExtraPoints); // for (Point2D point : newExtraPoints) //// for (Iterator it = newExtraPoints.iterator(); it.hasNext();) // { //// Point2D point = it.next(); // cellUpTrans.transform(point, point); // checkExtraPoints.add(point); // } // DBMath.transformRect(polyBnd, cellUpTrans); // polyArea.transform(cellUpTrans); // poly.transform(cellUpTrans); // } // else // { // Technology tech = np.getTechnology(); // Poly [] primPolyList = tech.getShapeOfNode(ni, true, ignoreCenterCuts, drcLayers); // int tot = primPolyList.length; // for(int j=0; j sIt = cell.searchIterator(ruleBnd); sIt.hasNext(); ) // { // RTBounds g = sIt.next(); // if (g == geom) continue; // if (!(g instanceof NodeInst)) continue; // NodeInst ni = (NodeInst)g; // NodeProto np = ni.getProto(); // if (NodeInst.isSpecialNode(ni)) continue; // Nov 4; // if (ni.isCellInstance()) // { // AffineTransform cellDownTrans = ni.transformIn(); // AffineTransform cellUpTrans = ni.transformOut(); // DBMath.transformRect(ruleBnd, cellDownTrans); // cellDownTrans.transform(points, 0, points, 0, points.length); // boolean allFound = allPointsContainedInLayer(geom, (Cell)np, ruleBnd, drcLayers, points, founds); // DBMath.transformRect(ruleBnd, cellUpTrans); // cellUpTrans.transform(points, 0, points, 0, points.length); // if (allFound) // return true; // } // else // { // Technology tech = np.getTechnology(); // Poly [] primPolyList = tech.getShapeOfNode(ni, true, ignoreCenterCuts, drcLayers); // int tot = primPolyList.length; // for(int j=0; j test sufficient to detect the poly resistor if (!np.getFunction().isResistor()) return false; // Get m1 port closer to poly2 (the other geometry) Poly [] metalList = tech.getShapeOfNode(ni, true, reportInfo.ignoreCenterCuts, m1Layer); for (Poly p : metalList) { int m1Net = getDRCNetNumber(netlist, p.getPort(), ni, cellGlobalIndex); if (m1Net == net) return true; // found same network! } return false; } /** * Method to see if the two boxes are active elements, connected to opposite * sides of a field-effect transistor that resides inside of the box area. * Returns true if so. */ private boolean activeOnTransistor(Poly poly1, Layer layer1, int net1, Poly poly2, Layer layer2, int net2, Cell cell, int globalIndex) { // networks must be different if (net1 == net2) return false; // layers must be active or active contact Layer.Function fun = layer1.getFunction(); int funExtras = layer1.getFunctionExtras(); if (!fun.isDiff()) { if (!fun.isContact() || (funExtras&Layer.Function.CONDIFF) == 0) return false; } funExtras = layer2.getFunctionExtras(); fun = layer2.getFunction(); if (!fun.isDiff()) { if (!fun.isContact() || (funExtras&Layer.Function.CONDIFF) == 0) return false; } // search for intervening transistor in the cell Rectangle2D bounds1 = poly1.getBounds2D(); Rectangle2D bounds2 = poly2.getBounds2D(); Rectangle2D result = new Rectangle2D.Double(); Rectangle2D.union(bounds1, bounds2, result); // Rectangle2D.union(bounds1, bounds2, bounds1) Area area = new Area(result); area.subtract(new Area(bounds1)); area.subtract(new Area(bounds2)); result = area.getBounds2D(); // Rectangle2D.intersect(bounds1, result, result); // Rectangle2D.intersect(bounds2, result, result); return activeOnTransistorRecurse(result, net1, net2, cell, globalIndex, DBMath.MATID); } private boolean activeOnTransistorRecurse(Rectangle2D bounds, int net1, int net2, Cell cell, int globalIndex, FixpTransform trans) { Netlist netlist = getCheckProto(cell).netlist; Rectangle2D subBounds = new Rectangle2D.Double(); for(Iterator sIt = cell.searchIterator(bounds); sIt.hasNext(); ) { Geometric g = sIt.next(); if (!(g instanceof NodeInst)) continue; NodeInst ni = (NodeInst)g; NodeProto np = ni.getProto(); if (ni.isCellInstance()) { FixpTransform rTransI = ni.rotateIn(); FixpTransform tTransI = ni.translateIn(); rTransI.preConcatenate(tTransI); subBounds.setRect(bounds); DBMath.transformRect(subBounds, rTransI); CheckInst ci = checkInsts.get(ni); int localIndex = globalIndex * ci.multiplier + ci.localIndex + ci.offset; boolean ret = activeOnTransistorRecurse(subBounds, net1, net2, (Cell)np, localIndex, trans); if (ret) return true; continue; } // must be a transistor if (!ni.getFunction().isFET()) continue; // must be inside of the bounding box of the desired layers Rectangle2D nodeBounds = ni.getBounds(); // Enough with checking if the transistor active covers 100% the union region // boolean newStrategy = nodeBounds.contains(bounds); double cX = nodeBounds.getCenterX(); double cY = nodeBounds.getCenterY(); // if (Job.getDebug()) // { // boolean oldS = !((cX < bounds.getMinX() || cX > bounds.getMaxX() || // cY < bounds.getMinY() || cY > bounds.getMaxY())); // // if (newStrategy != oldS) // System.out.println("Error in transistor coverage"); // } // if (!newStrategy) // continue; if (cX < bounds.getMinX() || cX > bounds.getMaxX() || cY < bounds.getMinY() || cY > bounds.getMaxY()) continue; // determine the poly port (MUST BE BETTER WAY!!!!) PortProto badport = np.getPort(0); Network badNet = netlist.getNetwork(ni, badport, 0); boolean on1 = false, on2 = false; for(Iterator it = ni.getPortInsts(); it.hasNext(); ) { PortInst pi = (PortInst)it.next(); PortProto po = pi.getPortProto(); String name = po.getName(); boolean found = false; boolean oldFound = false; Network piNet = netlist.getNetwork(pi); // ignore connections on poly/gate if (name.indexOf("poly") != -1) { found = true; //continue; } if (piNet == badNet) oldFound = true; if (Job.LOCALDEBUGFLAG && oldFound != found) System.out.println("Here is different in activeOnTransistorRecurse"); if (found) continue; Integer [] netNumbers = networkLists.get(piNet); int net = netNumbers[globalIndex].intValue(); if (net < 0) continue; if (net == net1) on1 = true; if (net == net2) on2 = true; } // if either side is not connected, ignore this if (!on1 || !on2) continue; // transistor found that connects to both actives return true; } return false; } /** * Method to crop the box on layer "nLayer", electrical index "nNet" * and bounds (lx-hx, ly-hy) against the nodeinst "ni". The geometry in nodeinst "ni" * that is being checked runs from (nlx-nhx, nly-nhy). Only those layers * in the nodeinst that are the same layer and the same electrical network * are checked. Returns true if the bounds are reduced * to nothing. */ private boolean cropNodeInst(NodeInst ni, int globalIndex, FixpTransform trans, Layer nLayer, int nNet, Geometric nGeom, Rectangle2D bound) { Technology tech = ni.getProto().getTechnology(); assert(!ni.getProto().getFunction().isPin()); Layer.Function.Set set = Layer.getMultiLayersSet(nLayer); Poly [] cropNodePolyList = tech.getShapeOfNode(ni, true, reportInfo.ignoreCenterCuts, set); convertPseudoLayers(ni, cropNodePolyList); int tot = cropNodePolyList.length; if (tot <= 0) return false; boolean [] rotated = new boolean[tot]; Arrays.fill(rotated, false); boolean isConnected = false; Netlist netlist = getCheckProto(ni.getParent()).netlist; for(int j=0; j= 0) { if (poly.getPort() == null) continue; // determine network for this polygon int net = getDRCNetNumber(netlist, poly.getPort(), ni, globalIndex); if (net >= 0 && net != nNet) continue; } isConnected = true; break; } if (!isConnected) return false; // get the description of the nodeinst layers boolean allgone = false; for(int j=0; j 0) { allgone = true; break; } if (temp < 0) { tinyNodeInst = ni; tinyGeometric = nGeom; } } return allgone; } /** * Method to crop away any part of layer "lay" of arcinst "ai" that coincides * with a similar layer on a connecting nodeinst. The bounds of the arcinst * are in the reference parameters (lx-hx, ly-hy). Returns false * normally, 1 if the arcinst is cropped into oblivion. */ private boolean cropArcInst(ArcInst ai, Layer lay, FixpTransform inTrans, Rectangle2D bounds, boolean overlap) { for(int i=0; i<2; i++) { // find the primitive nodeinst at the true end of the portinst PortInst pi = ai.getPortInst(i); PortOriginal fp = new PortOriginal(pi, inTrans); NodeInst ni = fp.getBottomNodeInst(); if (NodeInst.isSpecialNode(ni)) continue; // Dec 08 -> is a pin so ignore it NodeProto np = ni.getProto(); FixpTransform trans = fp.getTransformToTop(); Technology tech = np.getTechnology(); Poly [] cropArcPolyList = null; // No overlap means arc should be cropped to get away from other element // if (!overlap && np.getFunction() == PrimitiveNode.Function.PIN) // { // // Pins don't generate polygons // // Search for another arc and try to crop it with that geometry // List drcLayers = new ArrayList(1); // drcLayers.add(lay.getFunction()); // List arcPolys = new ArrayList(1); // int totalPolys = 0; // for (Iterator it = ni.getConnections(); it.hasNext(); ) // { // Connection con = (Connection)it.next(); // ArcInst arc = con.getArc(); // if (arc == ai) continue; // Poly[] polys = tech.getShapeOfArc(arc, null, null, drcLayers); // arcPolys.add(polys); // totalPolys += polys.length; // } // cropArcPolyList = new Poly[totalPolys]; // int destPos = 0; // for (Poly[] arcs : arcPolys) //// for (int j = 0; j < arcPolys.size(); j++) // { //// Poly[] arcs = arcPolys.get(j); // System.arraycopy(arcs, 0, cropArcPolyList, destPos, arcs.length); // destPos += arcs.length; // } // } // else Layer.Function.Set set = Layer.getMultiLayersSet(lay); cropArcPolyList = tech.getShapeOfNode(ni, false, reportInfo.ignoreCenterCuts, set); int tot = cropArcPolyList.length; for(int j=0; j 0) return true; if (temp < 0) { tinyNodeInst = ni; tinyGeometric = ai; } } } return false; } /** * Method to convert all Layer information in the Polys to be non-pseudo. * This is only done for pins that have exports but no arcs. * @param ni the NodeInst being converted. * @param pList an array of Polys with Layer information for the NodeInst. */ private void convertPseudoLayers(NodeInst ni, Poly [] pList) { if (!ni.getProto().getFunction().isPin()) return; if (ni.hasConnections()) return; // if (ni.getNumConnections() != 0) return; if (!ni.hasExports()) return; // if (ni.getNumExports() == 0) return; // for pins that are unconnected but have exports, convert them to real layers int tot = pList.length; for(int i=0; i it = cell.getNodes(); it.hasNext(); ) { NodeInst ni = it.next(); NodeProto np = ni.getProto(); if (np == drcNodeProto) //Generic.tech().drcNode) { // Must get polygon from getNodeShape otherwise it will miss // rings FixpTransform trans = ni.rotateOut(); Poly [] list = cell.getTechnology().getShapeOfNode(ni, true, true, null); assert(list.length == 1); list[0].transform(trans); Area thisArea = new Area(list[0]); if (area == null) area = thisArea; else area.add(thisArea); continue; } if (ni.isCellInstance()) { // examine contents accumulateExclusion((Cell)np); } }; reportInfo.exclusionMap.put(cell, area); } /************************************************************************************************************** * QuickAreaEnumerator abstract class **************************************************************************************************************/ private abstract class QuickAreaEnumerator extends HierarchyEnumerator.Visitor { Layer polyLayer; Layer.Function.Set activeLayers = new Layer.Function.Set(Layer.Function.DIFFP, Layer.Function.DIFFN); /** * Method to check whether the layer must be checked or not. It might be done by this layer on that network * @param layer * @return true is the layer is should be skipped */ boolean skipLayer(Layer layer) { boolean noMinArea = minAreaLayerMap.get(layer) == null; boolean noMinEnc = enclosedAreaLayerMap.get(layer) == null && spacingLayerMap.get(layer) == null; if (noMinArea && noMinEnc) return true; if (layer.getFunction().isContact()) // via*, polyCut, activeCut) return true; return false; } } /************************************************************************************************************** * QuickAreaEnumeratorSlow class **************************************************************************************************************/ private class QuickAreaEnumeratorSlow extends QuickAreaEnumerator { private GeometryHandler merge; QuickAreaEnumeratorSlow(GeometryHandler.GHMode mode) { // Merge is used by the brute force algorithm merge = GeometryHandler.createGeometryHandler(mode, topCell.getTechnology().getNumLayers()); } public boolean enterCell(HierarchyEnumerator.CellInfo info) { if (job != null && job.checkAbort()) return false; FixpTransform rTrans = info.getTransformToRoot(); Cell cell = info.getCell(); for(Iterator it = cell.getArcs(); it.hasNext(); ) { ArcInst ai = it.next(); Network aNet = info.getNetlist().getNetwork(ai, 0); // aNet is null if ArcProto is Artwork if (aNet == null) { continue; } Technology tech = ai.getProto().getTechnology(); Poly [] arcInstPolyList = tech.getShapeOfArc(ai); int tot = arcInstPolyList.length; for(int i=0; i cellsMap; private GeometryHandler.GHMode mode; QuickAreaEnumeratorLocal(GeometryHandler.GHMode mode) { this.mode = mode; cellsMap = new HashMap(); } public boolean enterCell(HierarchyEnumerator.CellInfo info) { if (job != null && job.checkAbort()) return false; Cell cell = info.getCell(); MTDRCAreaTool.GeometryHandlerLayerBucket bucket = cellsMap.get(cell); if (bucket == null) { bucket = new MTDRCAreaTool.GeometryHandlerLayerBucket(mode); cellsMap.put(cell, bucket); } else { assert(bucket.merged); return false; // done with this cell } for(Iterator it = info.getCell().getArcs(); it.hasNext(); ) { ArcInst ai = it.next(); Network aNet = info.getNetlist().getNetwork(ai, 0); // aNet is null if ArcProto is Artwork if (aNet == null) { continue; } Technology tech = ai.getProto().getTechnology(); Poly [] arcInstPolyList = tech.getShapeOfArc(ai); int tot = arcInstPolyList.length; for(int i=0; i





© 2015 - 2024 Weber Informatics LLC | Privacy Policy