📄 ercwellcheck.java
字号:
indexValues = 0; } static synchronized int getFreeIndex() { return indexValues++; } public int getIndex() { return index; } public NetValues() { index = getFreeIndex(); } public synchronized void merge(NetValues other) { if (this.index == other.index) return; other.index = this.index; } } // well contacts private static class WellCon { Point2D ctr; int netNum; NetValues wellNum; boolean onProperRail; PrimitiveNode.Function fun; } /** * Class to define an R-Tree leaf node for geometry in the blockage data structure. */ private static class WellBound implements RTBounds { private Rectangle2D bound; private NetValues netID; WellBound(Rectangle2D bound) { this.bound = bound; this.netID = null; } public Rectangle2D getBounds() { return bound; } public NetValues getNetID() { return netID; } public String toString() { return "Well Bound on net " + netID.getIndex(); } } private static class NetRails { boolean onGround; boolean onPower; } private static class WellNet { List<Point2D> pointsOnNet; List<WellCon> contactsOnNet; PrimitiveNode.Function fun; } /** * Comparator class for sorting Rectangle2D objects by their size. */ private static class RectangleBySize implements Comparator<Rectangle2D> { /** * Method to sort Rectangle2D objects by their size. */ public int compare(Rectangle2D b1, Rectangle2D b2) { double s1 = b1.getWidth() * b1.getHeight(); double s2 = b2.getWidth() * b2.getHeight(); if (s1 > s2) return -1; if (s1 < s2) return 1; return 0; } } private class NewWellCheckVisitor extends HierarchyEnumerator.Visitor { private Map<Cell,List<Rectangle2D>> essentialPWell; private Map<Cell,List<Rectangle2D>> essentialNWell; private Map<Network,NetRails> networkCache; public NewWellCheckVisitor() { essentialPWell = new HashMap<Cell,List<Rectangle2D>>(); essentialNWell = new HashMap<Cell,List<Rectangle2D>>(); networkCache = new HashMap<Network,NetRails>(); } public boolean enterCell(HierarchyEnumerator.CellInfo info) { // Checking if job is scheduled for abort or already aborted if (job != null && job.checkAbort()) return false; // make sure essential well areas are gathered Cell cell = info.getCell(); ensureCellCached(cell); return true; } public void exitCell(HierarchyEnumerator.CellInfo info) { // Checking if job is scheduled for abort or already aborted if (job != null && job.checkAbort()) return; // get the object for merging all of the wells in this cell Cell cell = info.getCell(); List<Rectangle2D> pWellsInCell = essentialPWell.get(cell); List<Rectangle2D> nWellsInCell = essentialNWell.get(cell); for(Rectangle2D b : pWellsInCell) { Rectangle2D bounds = new Rectangle2D.Double(b.getMinX(), b.getMinY(), b.getWidth(), b.getHeight()); DBMath.transformRect(bounds, info.getTransformToRoot()); pWellRoot = RTNode.linkGeom(null, pWellRoot, new WellBound(bounds)); } for(Rectangle2D b : nWellsInCell) { Rectangle2D bounds = new Rectangle2D.Double(b.getMinX(), b.getMinY(), b.getWidth(), b.getHeight()); DBMath.transformRect(bounds, info.getTransformToRoot()); nWellRoot = RTNode.linkGeom(null, nWellRoot, new WellBound(bounds)); } } public boolean visitNodeInst(Nodable no, HierarchyEnumerator.CellInfo info) { NodeInst ni = no.getNodeInst(); // look for well and substrate contacts PrimitiveNode.Function fun = ni.getFunction(); if (fun == PrimitiveNode.Function.WELL || fun == PrimitiveNode.Function.SUBSTRATE) { WellCon wc = new WellCon(); wc.ctr = ni.getTrueCenter(); AffineTransform trans = ni.rotateOut(); trans.transform(wc.ctr, wc.ctr); info.getTransformToRoot().transform(wc.ctr, wc.ctr); wc.fun = fun; PortInst pi = ni.getOnlyPortInst(); Netlist netList = info.getNetlist(); Network net = netList.getNetwork(pi); wc.onProperRail = false; wc.wellNum = null; if (net == null) wc.netNum = -1; else { wc.netNum = info.getNetID(net); // PWell: must be on ground or NWell: must be on power Network parentNet = net; HierarchyEnumerator.CellInfo cinfo = info; while (cinfo.getParentInst() != null) { parentNet = cinfo.getNetworkInParent(parentNet); cinfo = cinfo.getParentInfo(); } if (parentNet != null) { NetRails nr = networkCache.get(parentNet); if (nr == null) { nr = new NetRails(); networkCache.put(parentNet, nr); for (Iterator<Export> it = parentNet.getExports(); it.hasNext(); ) { Export exp = it.next(); if (exp.isGround()) nr.onGround = true; if (exp.isPower()) nr.onPower = true; } } boolean searchWell = (fun == PrimitiveNode.Function.WELL); if ((searchWell && nr.onGround) || (!searchWell && nr.onPower)) wc.onProperRail = true; } } wellCons.add(wc); } return true; } private void ensureCellCached(Cell cell) { List<Rectangle2D> pWellsInCell = essentialPWell.get(cell); List<Rectangle2D> nWellsInCell = essentialNWell.get(cell); if (pWellsInCell == null) { // gather all wells in the cell pWellsInCell = new ArrayList<Rectangle2D>(); nWellsInCell = new ArrayList<Rectangle2D>(); for(Iterator<NodeInst> it = cell.getNodes(); it.hasNext(); ) { NodeInst ni = it.next(); if (ni.isCellInstance()) continue; PrimitiveNode pn = (PrimitiveNode)ni.getProto(); if (!possiblePrimitives.contains(pn)) continue; // Getting only ercLayers Poly [] nodeInstPolyList = pn.getTechnology().getShapeOfNode(ni, true, true, ercLayers); int tot = nodeInstPolyList.length; for(int i=0; i<tot; i++) { Poly poly = nodeInstPolyList[i]; Layer layer = poly.getLayer(); AffineTransform trans = ni.rotateOut(); poly.transform(trans); Rectangle2D bound = poly.getBounds2D(); int wellType = getWellLayerType(layer); if (wellType == ERCPWell) pWellsInCell.add(bound); else if (wellType == ERCNWell) nWellsInCell.add(bound); } } for(Iterator<ArcInst> it = cell.getArcs(); it.hasNext(); ) { ArcInst ai = it.next(); ArcProto ap = ai.getProto(); if (!possiblePrimitives.contains(ap)) continue; // Getting only ercLayers Poly [] arcInstPolyList = ap.getTechnology().getShapeOfArc(ai, ercLayers); int tot = arcInstPolyList.length; for(int i=0; i<tot; i++) { Poly poly = arcInstPolyList[i]; Layer layer = poly.getLayer(); Rectangle2D bound = poly.getBounds2D(); int wellType = getWellLayerType(layer); if (wellType == ERCPWell) pWellsInCell.add(bound); else if (wellType == ERCNWell) nWellsInCell.add(bound); } } // eliminate duplicates eliminateDuplicates(pWellsInCell); eliminateDuplicates(nWellsInCell); // save results essentialPWell.put(cell, pWellsInCell); essentialNWell.put(cell, nWellsInCell); } } private void eliminateDuplicates(List<Rectangle2D> wbList) { // first sort by size Collections.sort(wbList, new RectangleBySize()); for(int i=0; i<wbList.size(); i++) { Rectangle2D b = wbList.get(i); for(int j=0; j<i; j++) { Rectangle2D prevB = wbList.get(j); if (prevB.contains(b)) { wbList.remove(i); i--; break; } } } } } private static final int ERCPWell = 1; private static final int ERCNWell = 2; private static final int ERCPSEUDO = 0; private static final Layer.Function[] ercLayersArray = { Layer.Function.WELLP, Layer.Function.WELL, Layer.Function.WELLN, Layer.Function.SUBSTRATE, Layer.Function.IMPLANTP, Layer.Function.IMPLANT, Layer.Function.IMPLANTN}; private static final Layer.Function.Set ercLayers = new Layer.Function.Set(ercLayersArray); /** * Method to return nonzero if layer "layer" is a well/select layer. * @return 1: P-Well, 2: N-Well */ private static int getWellLayerType(Layer layer) { Layer.Function fun = layer.getFunction(); if (layer.isPseudoLayer()) return ERCPSEUDO; if (fun == Layer.Function.WELLP) return ERCPWell; if (fun == Layer.Function.WELL || fun == Layer.Function.WELLN) return ERCNWell; return ERCPSEUDO; } // variables for the "old way" private GeometryHandler.GHMode mode; private Set<Cell> doneCells = new HashSet<Cell>(); // Mark if cells are done already. private Map<Cell,GeometryHandler> cellMerges = new HashMap<Cell,GeometryHandler>(); // make a map of merge information in each cell // well areas private static class WellArea { PolyBase poly; int netNum; int index; } private int doOldWay() { // enumerate the hierarchy below here WellCheckVisitor wcVisitor = new WellCheckVisitor(); HierarchyEnumerator.enumerateCell(cell, VarContext.globalContext, wcVisitor); // Checking if job is scheduled for abort or already aborted if (job != null && job.checkAbort()) return 0; // make a list of well and substrate areas List<WellArea> wellAreas = new ArrayList<WellArea>(); int wellIndex = 0; GeometryHandler topMerge = cellMerges.get(cell); for (Layer layer : topMerge.getKeySet()) { // Not sure if null goes here Collection<PolyBase> set = topMerge.getObjects(layer, false, true); for(PolyBase poly : set) { WellArea wa = new WellArea(); wa.poly = poly; wa.poly.setLayer(layer); wa.poly.setStyle(Poly.Type.FILLED); wa.index = wellIndex++; wellAreas.add(wa); } } boolean foundPWell = false; boolean foundNWell = false; for(WellArea wa : wellAreas) { int wellType = getWellLayerType(wa.poly.getLayer()); if (wellType != ERCPWell && wellType != ERCNWell) continue; // presume N-well PrimitiveNode.Function desiredContact = PrimitiveNode.Function.SUBSTRATE; String noContactError = "No N-Well contact found in this area"; int contactAction = ERC.getNWellCheck(); if (wellType == ERCPWell) { // P-well desiredContact = PrimitiveNode.Function.WELL; contactAction = ERC.getPWellCheck(); noContactError = "No P-Well contact found in this area"; foundPWell = true; } else foundNWell = true; // find a contact in the area boolean found = false; for(WellCon wc : wellCons) { if (wc.fun != desiredContact) continue; if (!wa.poly.getBounds2D().contains(wc.ctr)) continue; if (!wa.poly.contains(wc.ctr)) continue; wa.netNum = wc.netNum; found = true; break; } // if no contact, issue appropriate errors if (!found) { if (contactAction == 0) { errorLogger.logError(noContactError, wa.poly, cell, 0); } } } // make sure all of the contacts are on the same net for(WellCon wc : wellCons) { // -1 means not connected in hierarchyEnumerator::numberNets() if (wc.netNum == -1) { String errorMsg = "N-Well contact is floating"; if (wc.fun == PrimitiveNode.Function.WELL) errorMsg = "P-Well contact is floating"; errorLogger.logError(errorMsg, new EPoint(wc.ctr.getX(), wc.ctr.getY()), cell, 0); continue; } if (!wc.onProperRail) { if (wc.fun == PrimitiveNode.Function.WELL) { if (ERC.isMustConnectPWellToGround()) { errorLogger.logError("P-Well contact not connected to ground", new EPoint(wc.ctr.getX(), wc.ctr.getY()), cell, 0); } } else { if (ERC.isMustConnectNWellToPower()) { errorLogger.logError("N-Well contact not connected to power", new EPoint(wc.ctr.getX(), wc.ctr.getY()), cell, 0); } } } } // if just 1 N-Well contact is needed, see if it is there if (ERC.getNWellCheck() == 1 && foundNWell) { boolean found = false; for(WellCon wc : wellCons) { if (wc.fun == PrimitiveNode.Function.SUBSTRATE) { found = true; break; } } if (!found) { errorLogger.logError("No N-Well contact found in this cell", cell, 0); } } // if just 1 P-Well contact is needed, see if it is there if (ERC.getPWellCheck() == 1 && foundPWell) { boolean found = false; for(WellCon wc : wellCons) { if (wc.fun == PrimitiveNode.Function.WELL) { found = true; break; } } if (!found) { errorLogger.logError("No P-Well contact found in this cell", cell, 0); } } // make sure the wells are separated properly // Local storage of rules.. otherwise getSpacingRule is called too many times // THIS IS A DRC JOB .. not efficient if done here. if (ERC.isDRCCheck()) { Map<Layer,DRCTemplate> rulesCon = new HashMap<Layer,DRCTemplate>(); Map<Layer,DRCTemplate> rulesNonCon = new HashMap<Layer,DRCTemplate>(); for(WellArea wa : wellAreas) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -