123
107
/** layers to use for given arc functions */ private Map<Layer.Function,Layer> layerForFunction;
124
108
/** the layer to use for "polysilicon" geometry */ private Layer polyLayer;
125
109
/** temporary layers to use for geometric manipulation */ private Layer tempLayer1;
126
/** the layers to use for "active" geometry */ private Layer pActiveLayer, nActiveLayer;
110
/** the layers to use for "active" geometry */ private Layer activeLayer, pActiveLayer, nActiveLayer;
111
/** the layers to use for "select" geometry */ private Layer pSelectLayer, nSelectLayer;
127
112
/** the real "active" layers */ private Layer realPActiveLayer, realNActiveLayer;
128
/** associates arc prototypes with layers */ private Map<Layer,ArcProto> arcsForLayer;
113
/** the well and substrate layers */ private Layer wellLayer, substrateLayer;
114
/** associates arc prototypes with layers */ private Map<Layer,ArcProto> arcsForLayer;
129
115
/** map of extracted cells */ private Map<Cell,Cell> convertedCells;
130
116
/** map of cut layers to lists of polygons on that layer */ private Map<Layer,CutInfo> allCutLayers;
131
117
/** set of pure-layer nodes that are not processed */ private Set<PrimitiveNode> ignoreNodes;
132
118
/** set of contacts that are not used for extraction */ private Set<PrimitiveNode> bogusContacts;
133
/** list of Exports to restore after extraction */ private List<Export> exportsToRestore;
119
/** PrimitiveNodes for pdiff and ndiff */ private PrimitiveNode diffNode, pDiffNode, nDiffNode;
120
/** list of Exports to restore after extraction */ private List<Export> exportsToRestore;
134
121
/** auto-generated exports that may need better names */ private List<Export> generatedExports;
135
/** true if this is a P-well process (presume P-well) */ private boolean pWellProcess;
136
/** true if this is a N-well process (presume N-well) */ private boolean nWellProcess;
122
/** true if this is a P-well process (presume P-well) */ private boolean pSubstrateProcess;
123
/** true if this is a N-well process (presume N-well) */ private boolean nSubstrateProcess;
137
124
/** helper variables for computing N/P process factors */ private boolean hasWell, hasPWell, hasNWell;
138
125
/** true to unify N and P active layers */ private boolean unifyActive;
139
126
/** helper variables for computing N and P active unify */ private boolean haveNActive, havePActive;
305
305
validLayers = true;
307
307
if (!validLayers) ignoreNodes.add(np);
309
// determine diffusion nodes
310
Layer layer = np.getLayerIterator().next();
311
if (layer.getFunction() == Layer.Function.DIFF)
313
if (layer.getFunction() == Layer.Function.DIFFN)
315
if (layer.getFunction() == Layer.Function.DIFFP)
310
319
// determine if this is a "P-well" or "N-well" process
311
320
findMissingWells(cell, recursive, pat, activeHandling);
313
322
// find important layers
314
323
polyLayer = null;
315
pActiveLayer = nActiveLayer = null;
324
activeLayer = pActiveLayer = nActiveLayer = null;
316
325
realPActiveLayer = realNActiveLayer = null;
317
for(Iterator<Layer> it = tech.getLayers(); it.hasNext(); )
326
pSelectLayer = nSelectLayer = null;
327
wellLayer = substrateLayer = null;
328
for(Iterator<Layer> it = tech.getLayers(); it.hasNext(); )
319
330
Layer layer = it.next();
320
331
Layer.Function fun = layer.getFunction();
321
332
if (polyLayer == null && fun == Layer.Function.POLY1) polyLayer = layer;
324
if (pActiveLayer == null && fun.isDiff()) pActiveLayer = layer;
327
if (pActiveLayer == null && fun == Layer.Function.DIFFP) pActiveLayer = layer;
328
if (nActiveLayer == null && fun == Layer.Function.DIFFN) nActiveLayer = layer;
333
if (activeLayer == null && fun == Layer.Function.DIFF) activeLayer = layer;
334
if (pActiveLayer == null && fun == Layer.Function.DIFFP) pActiveLayer = layer;
335
if (nActiveLayer == null && fun == Layer.Function.DIFFN) nActiveLayer = layer;
330
336
if (realPActiveLayer == null && fun == Layer.Function.DIFFP) realPActiveLayer = layer;
331
337
if (realNActiveLayer == null && fun == Layer.Function.DIFFN) realNActiveLayer = layer;
338
if (pSelectLayer == null && fun == Layer.Function.IMPLANTP) pSelectLayer = layer;
339
if (nSelectLayer == null && fun == Layer.Function.IMPLANTN) nSelectLayer = layer;
340
if (pSubstrateProcess) // psubstrate
342
if (wellLayer == null && fun == Layer.Function.WELLN) wellLayer = layer;
343
if (substrateLayer == null && fun == Layer.Function.WELLP) substrateLayer = layer;
345
if (nSubstrateProcess) // nsubstrate
347
if (wellLayer == null && fun == Layer.Function.WELLP) wellLayer = layer;
348
if (substrateLayer == null && fun == Layer.Function.WELLN) substrateLayer = layer;
333
351
polyLayer = polyLayer.getNonPseudoLayer();
334
352
if (polyLayer != null)
335
353
tempLayer1 = polyLayer.getPseudoLayer();
336
pActiveLayer = pActiveLayer.getNonPseudoLayer();
337
if (unifyActive) nActiveLayer = pActiveLayer; else
338
nActiveLayer = nActiveLayer.getNonPseudoLayer();
354
if (pActiveLayer == null || nActiveLayer == null && activeLayer != null) {
356
pActiveLayer = nActiveLayer = activeLayer;
359
pActiveLayer = pActiveLayer.getNonPseudoLayer();
360
nActiveLayer = nActiveLayer.getNonPseudoLayer();
340
363
// figure out which arcs to use for a layer
341
364
arcsForLayer = new HashMap<Layer,ArcProto>();
523
547
extractTransistors(merge, originalMerge, newCell);
524
548
termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "Transistors");
526
// extend geometry that sticks out in space
528
if (!startSection(oldCell, "Extracting extensions...")) return null; // aborted
529
extendGeometry(merge, originalMerge, newCell, true);
530
termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "StickOuts");
532
// look for wires and pins
534
if (!startSection(oldCell, "Extracting wires...")) return null; // aborted
535
if (makeWires(merge, originalMerge, newCell)) return newCell;
536
termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "Wires");
538
// convert any geometry that connects two networks
540
if (!startSection(oldCell, "Extracting connections...")) return null; // aborted
541
extendGeometry(merge, originalMerge, newCell, false);
542
termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "Bridges");
544
// dump any remaining layers back in as extra pure layer nodes
546
if (!startSection(oldCell, "Extracting leftover geometry...")) return null; // aborted
547
convertAllGeometry(merge, originalMerge, newCell);
548
termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "Pures");
550
// reexport any that were there before
550
if (Extract.isUsePureLayerNodes()) {
551
// dump back in original routing layers
552
if (!startSection(oldCell, "Adding in original routing layers...")) return null;
553
addInRoutingLayers(oldCell, newCell, merge, originalMerge);
557
// extend geometry that sticks out in space
560
if (!startSection(oldCell, "Extracting extensions...")) return null; // aborted
561
extendGeometry(merge, originalMerge, newCell, true);
562
termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "StickOuts");
565
// look for wires and pins
567
if (!startSection(oldCell, "Extracting wires...")) return null; // aborted
568
if (makeWires(merge, originalMerge, newCell)) return newCell;
569
termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "Wires");
571
// convert any geometry that connects two networks
573
if (!startSection(oldCell, "Extracting connections...")) return null; // aborted
574
extendGeometry(merge, originalMerge, newCell, false);
575
termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "Bridges");
578
// dump any remaining layers back in as extra pure layer nodes
580
if (!startSection(oldCell, "Extracting leftover geometry...")) return null; // aborted
581
convertAllGeometry(merge, originalMerge, newCell);
582
termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "Pures");
584
// reexport any that were there before
551
585
if (!startSection(oldCell, "Adding connecting wires...")) return null; // aborted
552
586
cleanupExports(oldCell, newCell);
557
591
AffineTransform shrink = new AffineTransform(shrinkage, 0, 0, shrinkage, 0, 0);
558
592
originalUnscaledMerge.addMerge(originalMerge, shrink);
559
593
Set<ArcInst> allArcs = null;
562
allArcs = new HashSet<ArcInst>();
563
for(Iterator<ArcInst> it = newCell.getArcs(); it.hasNext(); )
564
allArcs.add(it.next());
566
AutoOptions prefs = new AutoOptions();
595
allArcs = new HashSet<ArcInst>();
596
for(Iterator<ArcInst> it = newCell.getArcs(); it.hasNext(); )
597
allArcs.add(it.next());
599
// make sure current arc is not universal arc, otherwise it makes the InteractiveRouter (used by AutoStitch) prefer that arc
600
if (User.getUserTool().getCurrentArcProto() == Generic.tech().universal_arc) {
601
User.getUserTool().setCurrentArcProto(newCell.getTechnology().getArcs().next());
604
// TODO: originalMerge passed to auto stitcher really needs to include subcell geometry too, in order
605
// for the auto-stitcher to know where it can place arcs. However, building and maintaining such a hashmap
606
// might take up a lot of memory.
607
AutoOptions prefs = new AutoOptions();
567
608
prefs.createExports = true;
568
AutoStitch.runAutoStitch(newCell, null, null, job, originalUnscaledMerge, null, false, prefs, !recursive);
609
AutoStitch.runAutoStitch(newCell, null, null, job, originalUnscaledMerge, null, false, true, prefs, !recursive, alignment);
611
// check all the arcs that auto-stitching added, and replace them by universal arcs if they are off-grid
612
if (alignment != null && (alignment.getWidth() > 0 || alignment.getHeight() > 0)) {
613
for(Iterator<ArcInst> it = newCell.getArcs(); it.hasNext(); ) {
614
ArcInst ai = it.next();
615
if (allArcs.contains(ai)) continue;
616
Rectangle2D bounds = ai.getBounds();
617
if (bounds.getMinX() % alignment.getWidth() != 0 || bounds.getMinY() % alignment.getHeight() != 0 ||
618
bounds.getMaxX() % alignment.getWidth() != 0 || bounds.getMaxY() % alignment.getHeight() != 0) {
620
Connection head = ai.getHead();
621
Connection tail = ai.getTail();
622
ArcInst newAi = ArcInst.makeInstanceBase(Generic.tech().universal_arc, 0, head.getPortInst(), tail.getPortInst(),
623
head.getLocation(), tail.getLocation(), null);
625
newAi.setHeadExtended(false);
626
newAi.setTailExtended(false);
572
636
for(Iterator<ArcInst> it = newCell.getArcs(); it.hasNext(); )
1060
1167
// now realize the wires
1061
1168
for(Centerline cl : lines)
1063
Point2D loc1Unscaled = new Point2D.Double();
1170
ap = findArcProtoForPoly(layer, poly, originalMerge);
1171
Point2D loc1Unscaled = new Point2D.Double();
1172
Point2D loc2Unscaled = new Point2D.Double();
1064
1173
PortInst pi1 = locatePortOnCenterline(cl, loc1Unscaled, layer, ap, true, newCell);
1065
Point2D loc2Unscaled = new Point2D.Double();
1174
Point2D loc1 = new Point2D.Double(scaleUp(loc1Unscaled.getX()), scaleUp(loc1Unscaled.getY()));
1066
1175
PortInst pi2 = locatePortOnCenterline(cl, loc2Unscaled, layer, ap, false, newCell);
1067
Point2D loc1 = new Point2D.Double(scaleUp(loc1Unscaled.getX()), scaleUp(loc1Unscaled.getY()));
1068
1176
Point2D loc2 = new Point2D.Double(scaleUp(loc2Unscaled.getX()), scaleUp(loc2Unscaled.getY()));
1070
1178
// make sure the wire fits
1071
1179
MutableBoolean headExtend = new MutableBoolean(true), tailExtend = new MutableBoolean(true);
1181
// adjust extension to get alignment right
1182
if (loc1.getX() == loc2.getX())
1184
// vertical arc: adjust extension to make sure top and bottom are on grid
1185
double loc1Y = loc1Unscaled.getY();
1186
double loc2Y = loc2Unscaled.getY();
1187
double halfWidth = cl.width/2/SCALEFACTOR;
1188
double loc1YExtend = loc1Y + (loc1Y < loc2Y ? -halfWidth : halfWidth);
1189
double loc2YExtend = loc2Y + (loc2Y < loc1Y ? -halfWidth : halfWidth);
1190
if (!isOnGrid(loc1YExtend, alignment.getHeight()) && isOnGrid(loc1Y, alignment.getHeight()))
1191
headExtend.setValue(false);
1192
if (!isOnGrid(loc2YExtend, alignment.getHeight()) && isOnGrid(loc2Y, alignment.getHeight()))
1193
tailExtend.setValue(false);
1194
} else if (loc1.getY() == loc2.getY())
1196
// horizontal arc: adjust extension to make sure left and right are on grid
1197
double loc1X = loc1Unscaled.getX();
1198
double loc2X = loc2Unscaled.getX();
1199
double halfWidth = cl.width/2/SCALEFACTOR;
1200
double loc1XExtend = loc1X + (loc1X < loc2X ? -halfWidth : halfWidth);
1201
double loc2XExtend = loc2X + (loc2X < loc1X ? -halfWidth : halfWidth);
1202
if (!isOnGrid(loc1XExtend, alignment.getWidth()) && isOnGrid(loc1X, alignment.getWidth()))
1203
headExtend.setValue(false);
1204
if (!isOnGrid(loc2XExtend, alignment.getWidth()) && isOnGrid(loc2X, alignment.getWidth()))
1205
tailExtend.setValue(false);
1072
1208
boolean fits = originalMerge.arcPolyFits(layer, loc1, loc2, cl.width, headExtend, tailExtend);
1073
1209
if (DEBUGCENTERLINES) System.out.println("FIT="+fits+" "+cl);
1118
// examine each wire layer, looking for a simple rectangle that covers it
1262
// add in pure layer node for remaining geom
1263
for (Layer layer : allLayers)
1265
List<PolyBase> polyList = getMergePolys(merge, layer, null);
1266
for(PolyBase poly : polyList)
1268
ArcProto ap = findArcProtoForPoly(layer, poly, originalMerge);
1269
if (ap == null) continue;
1270
PrimitiveNode pin = ap.findPinProto();
1272
List<NodeInst> niList = makePureLayerNodeFromPoly(poly, newCell, merge);
1273
merge.subtract(layer, poly);
1274
// connect up to enclosed pins
1275
for (NodeInst ni : niList)
1277
PortInst fPi = ni.getOnlyPortInst();
1278
Rectangle2D polyBounds = ni.getBounds();
1279
Rectangle2D searchBound = new Rectangle2D.Double(polyBounds.getMinX(), polyBounds.getMinY(),
1280
polyBounds.getWidth(), polyBounds.getHeight());
1281
for(Iterator<RTBounds> it = newCell.searchIterator(searchBound); it.hasNext(); )
1283
RTBounds geom = it.next();
1284
if (!(geom instanceof NodeInst)) continue;
1285
NodeInst oNi = (NodeInst)geom;
1286
if (oNi == ni) continue;
1287
if (oNi.getProto() != pin) continue;
1288
// make sure center of pin is in bounds
1289
if (!DBMath.pointInsideRect(oNi.getAnchorCenter(), searchBound)) continue;
1291
// replace arcs that end on pin to end on pure layer node
1292
for (Iterator<Connection> cit = oNi.getConnections(); cit.hasNext(); ) {
1293
Connection conn = cit.next();
1295
ArcInst ai = conn.getArc();
1296
if (ai.getProto() == Generic.tech().universal_arc) continue;
1298
if (conn instanceof HeadConnection) {
1299
oConn = ai.getTail();
1300
newAi = ArcInst.makeInstanceBase(ap, ai.getLambdaBaseWidth(), fPi, oConn.getPortInst(),
1301
conn.getLocation(), oConn.getLocation(), null);
1303
oConn = ai.getHead();
1304
newAi = ArcInst.makeInstanceBase(ap, ai.getLambdaBaseWidth(), oConn.getPortInst(), fPi,
1305
oConn.getLocation(), conn.getLocation(), null);
1307
if (newAi != null) {
1308
newAi.setHeadExtended(ai.isHeadExtended());
1309
newAi.setTailExtended(ai.isTailExtended());
1310
if (newAi.getLambdaLength() == 0)
1311
System.out.println("arc inst of zero length connecting pure layer nodes");
1314
String msg = "Cell " + newCell.describe(false) + ": Failed to replace arc " + ap.getName() +
1315
" from (" + conn.getLocation().getX() + "," +
1316
conn.getLocation().getY() + ") on node " + ni.describe(false) + " to (" +
1317
oConn.getLocation().getX() + "," + oConn.getLocation().getY() + ")";
1318
addErrorLog(newCell, msg, new EPoint(conn.getLocation().getX(), conn.getLocation().getY()),
1319
new EPoint(oConn.getLocation().getX(), oConn.getLocation().getY()));
1326
if (true) return false;
1328
// examine each wire layer, looking for a simple rectangle that covers it
1119
1329
for(Layer layer : allLayers)
1121
1331
// examine the geometry on the layer
1123
1333
for(PolyBase poly : polyList)
1125
1335
Rectangle2D bounds = poly.getBounds2D();
1337
// make sure polygon is in the merge
1126
1338
Poly rectPoly = new Poly(bounds);
1127
1339
if (!originalMerge.contains(layer, rectPoly)) continue;
1341
// grid align the edges of this rectangle
1342
double lX = bounds.getMinX()/SCALEFACTOR, hX = bounds.getMaxX()/SCALEFACTOR;
1343
double lY = bounds.getMinY()/SCALEFACTOR, hY = bounds.getMaxY()/SCALEFACTOR;
1344
double alignX = alignment.getWidth();
1345
double alignY = alignment.getHeight();
1346
if (!isOnGrid(lX, alignX)) lX = Math.ceil(lX / alignX) * alignX;
1347
if (!isOnGrid(hX, alignX)) hX = Math.floor(hX / alignX) * alignX;
1348
if (!isOnGrid(lY, alignY)) lY = Math.ceil(lY / alignY) * alignY;
1349
if (!isOnGrid(hY, alignY)) hY = Math.floor(hY / alignY) * alignY;
1350
if (lX >= hX || lY >= hY) continue;
1352
// grid align the center of this rectangle
1354
double cX = (lX + hX) / 2, cY = (lY + hY) / 2;
1355
if (!isOnGrid(cX, alignX))
1357
// try expanding to the right so center is aligned
1358
double cXright = Math.ceil(cX / alignX) * alignX;
1359
Poly testPoly = new Poly(cXright*SCALEFACTOR, cY*SCALEFACTOR, ((cXright-lX) * 2)*SCALEFACTOR, (hY-lY)*SCALEFACTOR);
1360
if (originalMerge.contains(layer, testPoly)) bounds = testPoly.getBounds2D(); else
1362
// try expanding to the left so center is aligned
1363
double cXleft = Math.floor(cX / alignX) * alignX;
1364
testPoly = new Poly(cXleft*SCALEFACTOR, cY*SCALEFACTOR, ((hX-cXleft) * 2)*SCALEFACTOR, (hY-lY)*SCALEFACTOR);
1365
if (originalMerge.contains(layer, testPoly)) bounds = testPoly.getBounds2D(); else
1367
// try contracting on the right so center is aligned
1368
testPoly = new Poly(cXright*SCALEFACTOR, cY*SCALEFACTOR, ((hX-cXright) * 2)*SCALEFACTOR, (hY-lY)*SCALEFACTOR);
1369
if (originalMerge.contains(layer, testPoly)) bounds = testPoly.getBounds2D(); else
1371
// try contracting on the left so center is aligned
1372
testPoly = new Poly(cXleft*SCALEFACTOR, cY*SCALEFACTOR, ((cXleft-lX) * 2)*SCALEFACTOR, (hY-lY)*SCALEFACTOR);
1373
if (originalMerge.contains(layer, testPoly)) bounds = testPoly.getBounds2D(); else
1378
if (bounds.getWidth() <= 0) continue;
1379
lX = bounds.getMinX()/SCALEFACTOR;
1380
hX = bounds.getMaxX()/SCALEFACTOR;
1384
if (!isOnGrid(cY, alignY))
1386
// try expanding upward so center is aligned
1387
double cYup = Math.ceil(cY / alignY) * alignY;
1388
Poly testPoly = new Poly(cX*SCALEFACTOR, cYup*SCALEFACTOR, (hX-lX)*SCALEFACTOR, ((cYup-lY) * 2)*SCALEFACTOR);
1389
if (originalMerge.contains(layer, testPoly)) bounds = testPoly.getBounds2D(); else
1391
// try expanding downward so center is aligned
1392
double cYdown = Math.floor(cY / alignY) * alignY;
1393
testPoly = new Poly(cX*SCALEFACTOR, cYdown*SCALEFACTOR, (hX-lX)*SCALEFACTOR, ((hY-cYdown) * 2)*SCALEFACTOR);
1394
if (originalMerge.contains(layer, testPoly)) bounds = testPoly.getBounds2D(); else
1396
// try contracting upward so center is aligned
1397
testPoly = new Poly(cX*SCALEFACTOR, cYup*SCALEFACTOR, (hX-lX)*SCALEFACTOR, ((hY-cYup) * 2)*SCALEFACTOR);
1398
if (originalMerge.contains(layer, testPoly)) bounds = testPoly.getBounds2D(); else
1400
// try contracting downward so center is aligned
1401
testPoly = new Poly(cX*SCALEFACTOR, cYdown*SCALEFACTOR, (hX-lX)*SCALEFACTOR, ((cYdown-lY) * 2)*SCALEFACTOR);
1402
if (originalMerge.contains(layer, testPoly)) bounds = testPoly.getBounds2D(); else
1407
if (bounds.getHeight() <= 0) continue;
1129
1411
// figure out which arc proto to use for the layer
1130
1412
ArcProto ap = findArcProtoForPoly(layer, poly, originalMerge);
1131
1413
if (ap == null) continue;
1133
1415
// determine the endpoints of the arc
1134
1416
Point2D loc1, loc2;
1135
double width = Math.min(bounds.getWidth(), bounds.getHeight());
1136
if (bounds.getWidth() > bounds.getHeight())
1418
if (bounds.getWidth() > bounds.getHeight())
1138
loc1 = new Point2D.Double((bounds.getMinX() + width/2) / SCALEFACTOR, bounds.getCenterY() / SCALEFACTOR);
1139
loc2 = new Point2D.Double((bounds.getMaxX() - width/2) / SCALEFACTOR, bounds.getCenterY() / SCALEFACTOR);
1421
width = bounds.getHeight();
1422
loc1 = new Point2D.Double((bounds.getMinX()) / SCALEFACTOR, bounds.getCenterY() / SCALEFACTOR);
1423
loc2 = new Point2D.Double((bounds.getMaxX()) / SCALEFACTOR, bounds.getCenterY() / SCALEFACTOR);
1142
loc1 = new Point2D.Double(bounds.getCenterX() / SCALEFACTOR, (bounds.getMinY() + width/2) / SCALEFACTOR);
1143
loc2 = new Point2D.Double(bounds.getCenterX() / SCALEFACTOR, (bounds.getMaxY() - width/2) / SCALEFACTOR);
1427
width = bounds.getWidth();
1428
loc1 = new Point2D.Double(bounds.getCenterX() / SCALEFACTOR, (bounds.getMinY()) / SCALEFACTOR);
1429
loc2 = new Point2D.Double(bounds.getCenterX() / SCALEFACTOR, (bounds.getMaxY()) / SCALEFACTOR);
1145
1431
PortInst pi1 = wantConnectingNodeAt(loc1, ap, width / SCALEFACTOR, newCell);
1146
1432
PortInst pi2 = wantConnectingNodeAt(loc2, ap, width / SCALEFACTOR, newCell);
1147
realizeArc(ap, pi1, pi2, loc1, loc2, width / SCALEFACTOR, false, false, merge);
1433
realizeArc(ap, pi1, pi2, loc1, loc2, width / SCALEFACTOR, true, true, merge);
1440
* Choose the right type of active for the active in the merge (takes into account select)
1442
private void fixActiveNodes(Cell cell)
1444
if (unifyActive) return; // no need to fix active
1445
if (ignoreActiveSelectWell) return;
1446
// if unifyActive is set, then Electric tech must only have one active
1447
// Otherwise, imported GDS may only have one active, but Electric has two, so
1448
// we need to fix that here.
1450
PrimitiveNode pDiffNode = null, nDiffNode = null;
1451
for (Iterator<PrimitiveNode> it = cell.getTechnology().getNodes(); it.hasNext(); )
1453
PrimitiveNode pn = it.next();
1454
if (pn.getFunction() == PrimitiveNode.Function.NODE) {
1455
Layer layer = pn.getLayerIterator().next();
1456
if (layer.getFunction() == Layer.Function.DIFFN)
1458
if (layer.getFunction() == Layer.Function.DIFFP)
1463
// first get all select layers
1464
PolyMerge merge = new PolyMerge();
1465
for (Iterator<NodeInst> it = cell.getNodes(); it.hasNext(); ) {
1466
NodeInst ni = it.next();
1467
if (ni.isCellInstance()) continue;
1468
Poly [] polys = tech.getShapeOfNode(ni);
1469
for(int j=0; j<polys.length; j++)
1471
Poly poly = polys[j];
1473
// get the layer for the geometry
1474
Layer layer = poly.getLayer();
1475
if (layer == null) continue;
1477
// make sure the geometric database is made up of proper layers
1478
layer = geometricLayer(layer);
1479
if (layer.getFunction() != Layer.Function.IMPLANTN && layer.getFunction() != Layer.Function.IMPLANTP) continue;
1481
merge.add(layer, poly);
1484
// now fix any active nodes
1485
for (Iterator<NodeInst> it = cell.getNodes(); it.hasNext(); ) {
1486
NodeInst ni = it.next();
1487
if (ni.isCellInstance()) continue;
1488
PrimitiveNode pn = (PrimitiveNode)ni.getProto();
1489
if (pn.getFunction() == PrimitiveNode.Function.NODE) {
1490
Layer nodeLayer = pn.getLayerIterator().next();
1491
PrimitiveNode newType = null;
1493
if (nodeLayer.getFunction() == Layer.Function.DIFFN) {
1494
// make sure n-diffusion is in n-select
1495
Poly [] polys = tech.getShapeOfNode(ni);
1496
for (Poly poly : polys) {
1497
if (merge.contains(pSelectLayer, poly)) {
1498
// switch it pactive
1499
newType = pDiffNode;
1504
if (nodeLayer.getFunction() == Layer.Function.DIFFP) {
1505
// make sure p-diffusion is in p-select
1506
Poly [] polys = tech.getShapeOfNode(ni);
1507
for (Poly poly : polys) {
1508
if (merge.contains(nSelectLayer, poly)) {
1509
// switch it nactive
1510
newType = nDiffNode;
1516
if (newType == null) continue;
1517
NodeInst newNi = NodeInst.newInstance(newType, ni.getAnchorCenter(), ni.getXSize(), ni.getYSize(), cell);
1518
if (ni.getTrace() != null && ni.getTrace().length > 0)
1520
EPoint [] origPoints = ni.getTrace();
1521
Point2D [] points = new Point2D[origPoints.length];
1522
// for some reason getTrace returns points relative to center, but setTrace expects absolute coords
1523
for (int i=0; i<origPoints.length; i++) {
1524
points[i] = new Point2D.Double(origPoints[i].getX()+ni.getAnchorCenterX(), origPoints[i].getY()+ni.getAnchorCenterY());
1526
newNi.setTrace(points);
1154
1534
* Method to figure out which ArcProto to use for a polygon on a layer.
1155
1535
* In the case of Active layers, it examines the well and select layers to figure out
1156
1536
* which arctive arc to use.
1209
1590
if (ap.getFunction() == neededFunction) return ap;
1595
Layer.Function fun = layer.getFunction();
1596
if (fun.isPoly() || fun.isMetal()) return arcsForLayer.get(layer);
1597
if (!fun.isDiff()) return null;
1599
ArrayList<Layer> requiredLayers = new ArrayList<Layer>();
1600
ArrayList<Layer> requiredAbsentLayers = new ArrayList<Layer>();
1602
// must further differentiate the active arcs...find implants
1603
Layer wellP = null, wellN = null, selectP = null, selectN = null;
1604
for(Layer l : originalMerge.getKeySet())
1606
if (l.getFunction() == Layer.Function.WELLP) wellP = l;
1607
if (l.getFunction() == Layer.Function.WELLN) wellN = l;
1610
// Active must have P-Select or N-Select
1611
if (pSelectLayer != null && originalMerge.intersects(pSelectLayer, poly)) {
1613
requiredLayers.add(activeLayer);
1615
requiredLayers.add(realPActiveLayer);
1616
requiredLayers.add(pSelectLayer);
1618
if (nSelectLayer != null && originalMerge.intersects(nSelectLayer, poly)) {
1620
requiredLayers.add(activeLayer);
1622
requiredLayers.add(realNActiveLayer);
1623
requiredLayers.add(nSelectLayer);
1626
// Active could either be an Active arc or a Well arc, depending on well type
1627
if (wellN == null || !originalMerge.intersects(wellN, poly))
1628
requiredAbsentLayers.add(wellN);
1629
if (wellN != null && originalMerge.intersects(wellN, poly))
1630
requiredLayers.add(wellN);
1632
// Active could either be an Active arc or a Well arc, depending on well type
1633
if (wellP == null || !originalMerge.intersects(wellP, poly))
1634
requiredAbsentLayers.add(wellP);
1635
if (wellP != null && originalMerge.intersects(wellP, poly))
1636
requiredLayers.add(wellP);
1638
// now find the arc with the desired function
1639
for(Iterator<ArcProto> aIt = tech.getArcs(); aIt.hasNext(); )
1641
ArcProto ap = aIt.next();
1642
List<Layer> apLayers = new ArrayList<Layer>();
1643
for (Iterator<Layer> layit = ap.getLayerIterator(); layit.hasNext(); )
1644
apLayers.add(layit.next());
1645
// make sure required layers exist
1646
boolean failed = false;
1647
for (Layer l : requiredLayers) {
1648
if (!apLayers.contains(l)) { failed = true; break; }
1650
if (failed) continue;
1651
for (Layer l : requiredAbsentLayers) {
1652
if (apLayers.contains(l)) { failed = true; break; }
1654
if (failed) continue;
1426
1892
int ang = GenMath.figureAngle(cl.start, cl.end);
1427
1893
double xOff = GenMath.cos(ang) * cl.width/2;
1428
1894
double yOff = GenMath.sin(ang) * cl.width/2;
1895
// double aliX = 1, aliY = 1;
1896
// if (alignment != null)
1898
// if (alignment.getWidth() > 0) aliX = scaleUp(alignment.getWidth());
1899
// if (alignment.getHeight() > 0) aliY = scaleUp(alignment.getHeight());
1431
1903
if (!isHub && cl.start.distance(cl.end) > cl.width)
1432
cl.setStart(cl.start.getX() + xOff, cl.start.getY() + yOff);
1433
NodeInst ni = wantNodeAt(cl.startUnscaled, pin, cl.width / SCALEFACTOR, newCell);
1905
//xOff = Math.floor(xOff / aliX) * aliX;
1906
//yOff = Math.floor(yOff / aliY) * aliY;
1907
// if shortening to allow ends extend will put the arc offgrid, do not do it
1908
if (xOff > 0 && (xOff % scaleUp(alignment.getWidth())) != 0) xOff = 0;
1909
if (yOff > 0 && (yOff % scaleUp(alignment.getHeight())) != 0) yOff = 0;
1910
cl.setStart(cl.start.getX() + xOff, cl.start.getY() + yOff);
1912
double size = pin.getFactoryDefaultLambdaBaseWidth();
1913
NodeInst ni = wantNodeAt(cl.startUnscaled, pin, size, newCell);
1434
1914
loc1.setLocation(cl.startUnscaled.getX(), cl.startUnscaled.getY());
1435
1915
piRet = ni.getOnlyPortInst();
1438
1918
if (!isHub && cl.start.distance(cl.end) > cl.width)
1920
//xOff = Math.ceil(xOff / aliX) * aliX;
1921
//yOff = Math.ceil(yOff / aliY) * aliY;
1922
// if shortening to allow ends extend will put the arc offgrid, do not do it
1923
if (xOff > 0 && (xOff % scaleUp(alignment.getWidth())) != 0) xOff = 0;
1924
if (yOff > 0 && (yOff % scaleUp(alignment.getHeight())) != 0) yOff = 0;
1439
1925
cl.setEnd(cl.end.getX() - xOff, cl.end.getY() - yOff);
1440
1927
NodeInst ni = wantNodeAt(cl.endUnscaled, pin, cl.width / SCALEFACTOR, newCell);
1441
1928
loc1.setLocation(cl.endUnscaled.getX(), cl.endUnscaled.getY());
1442
1929
piRet = ni.getOnlyPortInst();
1935
private void gridAlignCenterline(Centerline cl, boolean startSide)
1937
// // grid align the edges
1938
// double halfWidth = cl.width / 2;
1939
//halfWidth = 0; // is this right?
1940
// if (cl.start.getX() == cl.end.getX())
1942
// // vertical arc: make sure ends align in Y
1943
// int ali = (int)Math.round(alignment.getHeight() * SCALEFACTOR);
1944
// if (ali == 0) return;
1947
// // adjust the "start" end
1948
// if (cl.start.getY() < cl.end.getY())
1950
// // start on left: compute edge below it
1951
// double edge = cl.start.getY() - halfWidth;
1952
// cl.setStart(cl.start.getX(), Math.ceil(edge / ali) * ali + halfWidth);
1955
// // start on right: compute edge above it
1956
// double edge = cl.start.getY() + halfWidth;
1957
// cl.setStart(cl.start.getX(), Math.floor(edge / ali) * ali - halfWidth);
1961
// // adjust the "end" end
1962
// if (cl.end.getY() < cl.start.getY())
1964
// // end on left: compute edge below it
1965
// double edge = cl.end.getY() - halfWidth;
1966
// cl.setEnd(cl.end.getX(), Math.ceil(edge / ali) * ali + halfWidth);
1969
// // end on right: compute edge above it
1970
// double edge = cl.end.getY() + halfWidth;
1971
// cl.setEnd(cl.end.getX(), Math.floor(edge / ali) * ali - halfWidth);
1974
// } else if (cl.start.getY() == cl.end.getY())
1976
// // horizontal arc: make sure ends align in X
1977
// int ali = (int)Math.round(alignment.getWidth() * SCALEFACTOR);
1978
// if (ali == 0) return;
1981
// // adjust the "start" end
1982
// if (cl.start.getX() < cl.end.getX())
1984
// // start on left: compute edge below it
1985
// double edge = cl.start.getX() - halfWidth;
1986
// cl.setStart(Math.ceil(edge / ali) * ali + halfWidth, cl.start.getY());
1989
// // start on right: compute edge above it
1990
// double edge = cl.start.getX() + halfWidth;
1991
// cl.setStart(Math.floor(edge / ali) * ali - halfWidth, cl.start.getY());
1995
// // adjust the "end" end
1996
// if (cl.end.getX() < cl.start.getX())
1998
// // end on left: compute edge below it
1999
// double edge = cl.end.getX() - halfWidth;
2000
// cl.setEnd(Math.ceil(edge / ali) * ali + halfWidth, cl.end.getY());
2003
// // end on right: compute edge above it
2004
// double edge = cl.end.getX() + halfWidth;
2005
// cl.setEnd(Math.floor(edge / ali) * ali - halfWidth, cl.end.getY());
1448
2011
private List<PortInst> findPortInstsTouchingPoint(Point2D pt, Layer layer, Cell newCell, ArcProto ap)
1450
2013
List<PortInst> touchingNodes = new ArrayList<PortInst>();
1774
2346
double cutLimit = Math.ceil(Math.max(pv.multicutSep1D, pv.multicutSep2D) +
1775
2347
Math.max(pv.multicutSizeX, pv.multicutSizeY)) * SCALEFACTOR;
1776
2348
boolean foundMore = true;
2349
double xspacing = 0, yspacing = 0;
1779
2352
foundMore = false;
1780
Rectangle2D searchArea = new Rectangle2D.Double(multiCutBounds.getMinX()-cutLimit, multiCutBounds.getMinY()-cutLimit,
2353
Rectangle2D searchArea = new Rectangle2D.Double(multiCutBounds.getMinX()-cutLimit, multiCutBounds.getMinY()-cutLimit,
1781
2354
multiCutBounds.getWidth() + cutLimit*2, multiCutBounds.getHeight() + cutLimit*2);
1782
for(RTNode.Search sea = new RTNode.Search(searchArea, cInfo.getRTree(), true); sea.hasNext(); )
2356
Rectangle2D searchArea2 = new Rectangle2D.Double(searchArea.getMinX()/SCALEFACTOR, searchArea.getMinY()/SCALEFACTOR,
2357
searchArea.getWidth()/SCALEFACTOR, searchArea.getHeight()/SCALEFACTOR);
2358
System.out.println("Checking search area "+searchArea2);
2360
for(RTNode.Search sea = new RTNode.Search(searchArea, cInfo.getRTree(), true); sea.hasNext(); )
1784
2362
CutBound cBound = (CutBound)sea.next();
1785
2363
if (cutsInArea.contains(cBound.cut)) continue;
1786
2364
Rectangle2D bound = cBound.getBounds();
1787
2365
if (!searchArea.contains(bound.getCenterX(), bound.getCenterY())) continue;
1789
double lX = Math.min(multiCutBounds.getMinX(), bound.getMinX());
2367
// use only cuts at a spacing that matches (a multiple of) the nearest contact spacing
2368
double distX = cut.getCenterX() - bound.getCenterX();
2369
double distY = cut.getCenterY() - bound.getCenterY();
2371
if (xspacing == 0) xspacing = distX;
2372
else if (distX % xspacing != 0) continue;
2373
if (yspacing == 0) yspacing = distY;
2374
else if (distY % yspacing != 0) continue;
2377
// make sure cuts are in a contiguous array at the initial spacing
2378
if (furthestX == 0) furthestX = distX;
2379
if (furthestY == 0) furthestY = distY;
2380
if (distX > furthestX) {
2381
if (distX == furthestX + xspacing)
2382
furthestX = distX; // this is the next one on grid
2384
continue; // on grid, but not contiguous
2386
if (distY > furthestY) {
2387
if (distY == furthestY + yspacing)
2388
furthestY = distY; // this is the next one on grid
2390
continue; // on grid, but not contiguous
2393
// record height of first column
2394
if (maxColumnHeight == 0 && distX != 0) {
2395
// first contact of the second column
2396
maxColumnHeight = furthestY;
2400
double lX = Math.min(multiCutBounds.getMinX(), bound.getMinX());
1790
2401
double hX = Math.max(multiCutBounds.getMaxX(), bound.getMaxX());
1791
2402
double lY = Math.min(multiCutBounds.getMinY(), bound.getMinY());
1792
2403
double hY = Math.max(multiCutBounds.getMaxY(), bound.getMaxY());
1938
2565
root = RTNode.linkGeom(null, root, ni);
1940
2567
// recursively scan the R-Tree, merging geometry on created nodes and removing them from the main merge
1941
PolyMerge subtractMerge = new PolyMerge();
1942
extractContactNodes(root, merge, subtractMerge, 0, contactNodes.size());
1943
merge.subtractMerge(subtractMerge);
2568
if (!Extract.isUsePureLayerNodes())
2570
PolyMerge subtractMerge = new PolyMerge();
2571
extractContactNodes(root, merge, subtractMerge, 0, contactNodes.size());
2572
merge.subtractMerge(subtractMerge);
2578
* Multi-cut vias must be rectangular - get the largest rectangle that fits in the set of vias,
2579
* that includes the initial via
2580
* @param vias set of vias
2581
* @param initialVia the initial via
2582
* @param xspacing x spacing between vias
2583
* @param yspacing y spacing between vias
2584
* @param bounds bounds of all the vias
2585
* @return the subset of vias that form a contiguous rectangle, containing the initial via
2587
private Set<PolyBase> getLargestRectangleOfVias(Set<PolyBase> vias, PolyBase initialVia, double xspacing, double yspacing, Rectangle2D bounds)
2589
xspacing = Math.abs(xspacing);
2590
yspacing = Math.abs(yspacing);
2591
if (xspacing == 0) xspacing = SCALEFACTOR;
2592
if (yspacing == 0) yspacing = SCALEFACTOR;
2593
int numViasWide = (int)Math.ceil(bounds.getWidth() / xspacing);
2594
int numViasHigh = (int)Math.ceil(bounds.getHeight() / yspacing);
2595
PolyBase [][] viaMap = new PolyBase[numViasWide][numViasHigh];
2596
int nomX = 0, nomY = 0;
2598
for (int x=0; x<numViasWide; x++) {
2599
Arrays.fill(viaMap[x], null);
2603
for (PolyBase via : vias) {
2604
int x = (int)((via.getCenterX() - bounds.getMinX()) / xspacing);
2605
int y = (int)((via.getCenterY() - bounds.getMinY()) / yspacing);
2607
if (via == initialVia) {
2611
// find maxY and minY from initial via
2612
int maxY = nomY, minY = nomY;
2613
boolean initial = true;
2614
for (int x=0; x<numViasWide; x++) {
2615
if (viaMap[x][nomY] == null) continue; // skip this column, will be taken into account in X max/min
2618
for (int y=nomY; y<numViasHigh; y++) {
2619
if (viaMap[x][y] == null) break;
2622
if (initial) maxY = colMaxY; // initial column
2623
else if (colMaxY < maxY) maxY = colMaxY;
2626
for (int y=nomY; y>=0; y--) {
2627
if (viaMap[x][y] == null) break;
2630
if (initial) minY = colMinY; // initial column
2631
else if (colMinY > minY) minY = colMinY;
2635
// find maxX and minX from initial via
2636
int maxX = nomX, minX = nomX;
2638
for (int y=0; y<numViasHigh; y++) {
2639
if (viaMap[nomX][y] == null) continue; // skip this row, will be taken into account in Y max/min
2642
for (int x=nomX; x<numViasWide; x++) {
2643
if (viaMap[x][y] == null) break;
2646
if (initial) maxX = colMaxX; // initial row
2647
else if (colMaxX < maxX) maxX = colMaxX;
2650
for (int x=nomX; x>=0; x--) {
2651
if (viaMap[x][y] == null) break;
2654
if (initial) minX = colMinX; // initial row
2655
else if (colMinX > minX) minX = colMinX;
2660
Set<PolyBase> rectVias = new HashSet<PolyBase>();
2661
for (int x=minX; x<=maxX; x++) {
2662
for (int y=minY; y<=maxY; y++) {
2663
rectVias.add(viaMap[x][y]);
1948
2670
* Method to create the biggest contact node in a given location.
1949
2671
* @param pNp the type of node to create.
1950
2672
* @param cutVariation the contact cut spacing rule.
3509
4429
altNewStart.setLocation(newStart); altNewEnd.setLocation(intersect);
3510
4430
newStart = intersect;
3511
4431
extendAltEnd = extendStart = both[b].width / 2;
4432
if (offgrid && !makeT) {
4433
if (internalIntersect) {
4434
// adjust closer end point out of intersection area
4435
double diffX = altNewStart.getX() - intersect.getX();
4436
double diffY = altNewStart.getY() - intersect.getY();
4437
newStart = new Point2D.Double(intersect.getX() - diffX, intersect.getY() - diffY);
4438
altNewEnd.setLocation(intersect.getX() + diffX, intersect.getY() + diffY);
4440
newStart.setLocation(altNewStart);
4442
extendAltEnd = extendStart = Math.abs(betterExtension);
4444
else if (!makeT && betterExtension < extendStart) {
4445
// wire will not have ends extended, add in extra wire to account for non-end extension
4446
Centerline newCl = new Centerline(both[b].width, altNewStart, intersect);
4447
newCl.startHub = false;
4448
newCl.endHub = true;
4449
if (newCl.start.distance(newCl.end) > 0)
4450
extraCenterlines.add(newCl);
4452
} else // case: distToEnd <= distToStart
3514
4454
betterExtension = newEnd.distance(intersect);
3515
4455
altNewStart.setLocation(intersect); altNewEnd.setLocation(newEnd);
3516
4456
newEnd = intersect;
3517
4457
extendAltStart = extendEnd = both[b].width / 2;
4458
if (offgrid && !makeT) {
4459
if (internalIntersect) {
4460
double diffX = altNewEnd.getX() - intersect.getX();
4461
double diffY = altNewEnd.getY() - intersect.getY();
4462
newEnd = new Point2D.Double(intersect.getX() - diffX, intersect.getY() - diffY);
4463
altNewStart.setLocation(intersect.getX() + diffX, intersect.getY() + diffY);
4465
newEnd.setLocation(altNewEnd);
4467
extendAltStart = extendEnd = Math.abs(betterExtension);
4469
else if (!makeT && betterExtension < extendEnd) {
4470
// wire will not have ends extended, add in extra wire to account for non-end extension
4471
Centerline newCl = new Centerline(both[b].width, intersect, altNewEnd);
4472
newCl.startHub = true;
4473
newCl.endHub = false;
4474
if (newCl.start.distance(newCl.end) > 0)
4475
extraCenterlines.add(newCl);
3519
4478
Poly extended = Poly.makeEndPointPoly(newStart.distance(newEnd), both[b].width, both[b].angle,
3520
4479
newStart, extendStart, newEnd, extendEnd, Poly.Type.FILLED);
3790
4754
possibleEnd[p] = edgeCtrs[endPt];
3791
4755
length = edgeCtrs[startPt].distance(edgeCtrs[endPt]);
4759
// get the centerline points
4760
double psX = possibleStart[p].getX();
4761
double psY = possibleStart[p].getY();
4762
double peX = possibleEnd[p].getX();
4763
double peY = possibleEnd[p].getY();
4766
// grid-align the centerline points
4767
double xGrid = scaleUp(alignment.getWidth());
4768
double yGrid = scaleUp(alignment.getHeight());
4769
if (!isOnGrid(psX, xGrid))
4771
if (psX > peX) psX = Math.floor(psX / xGrid) * xGrid; else
4772
psX = Math.ceil(psX / xGrid) * xGrid;
4774
if (!isOnGrid(psY, yGrid))
4776
if (psY > peY) psY = Math.floor(psY / yGrid) * yGrid; else
4777
psY = Math.ceil(psY / yGrid) * yGrid;
4779
if (!isOnGrid(peX, xGrid))
4781
if (peX > psX) peX = Math.floor(peX / xGrid) * xGrid; else
4782
peX = Math.ceil(peX / xGrid) * xGrid;
4784
if (!isOnGrid(peY, yGrid))
4786
if (peY > psY) peY = Math.floor(peY / yGrid) * yGrid; else
4787
peY = Math.ceil(peY / yGrid) * yGrid;
3794
4791
// create the centerline
3795
Centerline newCL = new Centerline(width, possibleStart[p], possibleEnd[p]);
3796
if (newCL.angle >= 0) centerlines.add(newCL);
3797
if (DEBUGCENTERLINES) System.out.println(" MAKE "+newCL.toString());
4792
Point2D ps = new Point2D.Double(psX, psY);
4793
Point2D pe = new Point2D.Double(peX, peY);
4794
Centerline newCL = new Centerline(width, ps, pe);
4795
if (newCL.angle >= 0) {
4796
// check for redundant centerlines, favor centerlines that extend to external geometry
4797
boolean comparisonDone = false;
4798
for (int ci=0; ci < centerlines.size(); ci++) {
4799
Centerline acl = centerlines.get(ci);
4801
if (acl.getBounds().equals(newCL.getBounds())) {
4803
// check if they are perpendicular - if not, they are exactly redundant
4804
Centerline horCL = null, verCL = null;
4805
if (acl.start.getX() == acl.end.getX()) verCL = acl;
4806
if (acl.start.getY() == acl.end.getY()) horCL = acl;
4807
if (newCL.start.getX() == newCL.end.getX()) verCL = newCL;
4808
if (newCL.start.getY() == newCL.end.getY()) horCL = newCL;
4809
if (horCL == null || verCL == null) {
4810
comparisonDone = true;
4811
break; // not perpendicular
4814
Rectangle2D bounds = acl.getBounds();
4815
int favorHor = 0, favorVer = 0;
4817
// check horizontal extensions
4818
Rectangle2D boundsE = new Rectangle2D.Double(bounds.getX(), bounds.getY(),
4819
bounds.getWidth()+1.0/SCALEFACTOR, bounds.getHeight());
4820
Rectangle2D boundsW = new Rectangle2D.Double(bounds.getX()-1.0/SCALEFACTOR, bounds.getY(),
4821
bounds.getWidth()+1.0/SCALEFACTOR, bounds.getHeight());
4822
if (originalMerge.contains(poly.getLayer(), new PolyBase(boundsE)))
4824
if (originalMerge.contains(poly.getLayer(), new PolyBase(boundsW)))
4827
// check vertical extensions
4828
Rectangle2D boundsN = new Rectangle2D.Double(bounds.getX(), bounds.getY(),
4829
bounds.getWidth(), bounds.getHeight()+1.0/SCALEFACTOR);
4830
Rectangle2D boundsS = new Rectangle2D.Double(bounds.getX(), bounds.getY()-1.0/SCALEFACTOR,
4831
bounds.getWidth(), bounds.getHeight()+1.0/SCALEFACTOR);
4832
if (originalMerge.contains(poly.getLayer(), new PolyBase(boundsN)))
4834
if (originalMerge.contains(poly.getLayer(), new PolyBase(boundsS)))
4837
if (favorHor > favorVer) {
4838
if (centerlines.contains(verCL)) {
4839
if (DEBUGCENTERLINES)
4840
System.out.println("***REMOVE "+verCL.toString()+" WHICH IS SUBOPTIMAL");
4841
centerlines.remove(verCL);
4843
if (!centerlines.contains(horCL)) {
4844
if (DEBUGCENTERLINES) System.out.println(" MAKE "+newCL.toString());
4845
centerlines.add(horCL);
4847
comparisonDone = true;
4849
if (favorVer > favorHor) {
4850
if (centerlines.contains(horCL)) {
4851
if (DEBUGCENTERLINES)
4852
System.out.println("***REMOVE "+horCL.toString()+" WHICH IS SUBOPTIMAL");
4853
centerlines.remove(horCL);
4855
if (!centerlines.contains(verCL)) {
4856
if (DEBUGCENTERLINES) System.out.println(" MAKE "+newCL.toString());
4857
centerlines.add(verCL);
4859
comparisonDone = true;
4864
if (!comparisonDone) {
4865
centerlines.add(newCL);
4866
if (DEBUGCENTERLINES) System.out.println(" MAKE "+newCL.toString());
3958
5037
if (width > height)
3960
5039
// make a horizontal arc
3961
end1 = new Point2D.Double((polyBounds.getMinX()+height/2) / SCALEFACTOR, polyBounds.getCenterY() / SCALEFACTOR);
3962
end2 = new Point2D.Double((polyBounds.getMaxX()-height/2) / SCALEFACTOR, polyBounds.getCenterY() / SCALEFACTOR);
5040
end1 = new Point2D.Double((polyBounds.getMinX()), polyBounds.getCenterY());
5041
end2 = new Point2D.Double((polyBounds.getMaxX()), polyBounds.getCenterY());
3966
5045
// make a vertical arc
3967
end1 = new Point2D.Double(polyBounds.getCenterX() / SCALEFACTOR, (polyBounds.getMinY()+width/2) / SCALEFACTOR);
3968
end2 = new Point2D.Double(polyBounds.getCenterX() / SCALEFACTOR, (polyBounds.getMaxY()-width/2) / SCALEFACTOR);
5046
end1 = new Point2D.Double(polyBounds.getCenterX(), (polyBounds.getMinY()));
5047
end2 = new Point2D.Double(polyBounds.getCenterX(), (polyBounds.getMaxY()));
3971
NodeInst ni1 = createNode(np, end1, size, size, null, newCell);
3972
NodeInst ni2 = createNode(np, end2, size, size, null, newCell);
3973
MutableBoolean headExtend = new MutableBoolean(true), tailExtend = new MutableBoolean(true);
5050
MutableBoolean headExtend = new MutableBoolean(false), tailExtend = new MutableBoolean(false);
3974
5051
if (originalMerge.arcPolyFits(layer, end1, end2, size, headExtend, tailExtend))
5054
end1 = new Point2D.Double(end1.getX() / SCALEFACTOR, end1.getY() / SCALEFACTOR);
5055
end2 = new Point2D.Double(end2.getX() / SCALEFACTOR, end2.getY() / SCALEFACTOR);
5056
size = size / SCALEFACTOR;
5058
NodeInst ni1 = createNode(np, end1, size, size, null, newCell);
5059
NodeInst ni2 = createNode(np, end2, size, size, null, newCell);
3976
5060
realizeArc(ap, ni1.getOnlyPortInst(), ni2.getOnlyPortInst(), end1, end2,
3977
5061
size, !headExtend.booleanValue(), !tailExtend.booleanValue(), merge);
5063
System.out.println("Arc "+layer.getName()+" did not fit at "+polyBounds.getMinX()/SCALEFACTOR+","+polyBounds.getMinY()/SCALEFACTOR);
3984
5070
// just generate a pure-layer node
3985
List<NodeInst> niList = makePureLayerNodeFromPoly(poly, newCell);
3986
if (niList == null) continue;
5071
List<NodeInst> niList = makePureLayerNodeFromPoly(poly, newCell, originalMerge);
5072
// make well or implant hard to select
5073
if (poly.getLayer().getFunction().isSubstrate() || poly.getLayer().getFunction().isImplant()) {
5074
for (NodeInst ni : niList) ni.setHardSelect();
5077
if (niList == null) continue;
3988
5079
// connect to the rest if possible
3989
5080
if (ap != null) for(NodeInst ni : niList)
4056
5147
" tiny polygons (use Network Preferences to control tiny polygon limit)");
5151
* Method to add back in original routing layers as pure layer nodes
5152
* @param oldCell the original imported cell
5153
* @param newCell the new cell
5154
* @param merge the remaining layers to create
5155
* @param originalMerge the original set of layers
5157
private void addInRoutingLayers(Cell oldCell, Cell newCell, PolyMerge merge, PolyMerge originalMerge)
5159
Map<Layer,List<NodeInst>> newNodes = new HashMap<Layer,List<NodeInst>>();
5161
// create new nodes as copy of old nodes
5162
for (Iterator<NodeInst> nit = oldCell.getNodes(); nit.hasNext(); )
5164
NodeInst ni = nit.next();
5165
NodeProto np = ni.getProto();
5166
if (!(np instanceof PrimitiveNode)) continue;
5167
PrimitiveNode pn = (PrimitiveNode)np;
5168
if (pn.getFunction() == PrimitiveNode.Function.NODE)
5170
Layer layer = pn.getLayerIterator().next();
5171
Layer.Function fun = layer.getFunction();
5172
if (fun.isPoly() || fun.isMetal() || fun.isDiff())
5174
List<NodeInst> newNis = new ArrayList<NodeInst>();
5175
// create same node in new cell
5176
if (ni.getTrace() != null && ni.getTrace().length > 0)
5178
EPoint [] origPoints = ni.getTrace();
5179
Point2D [] points = new Point2D[origPoints.length];
5180
// for some reason getTrace returns points relative to center, but setTrace expects absolute coords
5181
for (int i=0; i<origPoints.length; i++) {
5182
points[i] = new Point2D.Double(origPoints[i].getX()+ni.getAnchorCenterX(), origPoints[i].getY()+ni.getAnchorCenterY());
5185
boolean BREAKUPTRACE = true;
5187
PolyBase poly = new PolyBase(points);
5188
poly.setLayer(layer);
5192
// irregular shape: break it up with simpler polygon merging algorithm
5193
GeometryHandler thisMerge = GeometryHandler.createGeometryHandler(GeometryHandler.GHMode.ALGO_SWEEP, 1);
5194
thisMerge.add(layer, poly);
5195
thisMerge.postProcess(true);
5197
Collection<PolyBase> set = ((PolySweepMerge)thisMerge).getPolyPartition(layer);
5198
for(PolyBase simplePoly : set)
5200
PolyBase simplePolyScaledUp = scaleUpPoly(simplePoly);
5201
pn = getActiveNodeType(layer, simplePolyScaledUp, originalMerge, pn);
5202
layer = pn.getLayerIterator().next();Rectangle2D polyBounds = simplePoly.getBounds2D();
5203
NodeInst newNi = NodeInst.makeInstance(pn, simplePoly.getCenter(), polyBounds.getWidth(), polyBounds.getHeight(),
5205
if (newNi == null) continue;
5209
PolyBase polyScaledUp = scaleUpPoly(poly);
5210
pn = getActiveNodeType(layer, polyScaledUp, originalMerge, pn);
5211
NodeInst newNi = NodeInst.makeInstance(pn, ni.getAnchorCenter(), ni.getXSize(), ni.getYSize(), newCell);
5212
if (newNi != null) {
5214
newNi.setTrace(points);
5218
PolyBase poly = new PolyBase(ni.getBounds());
5219
PolyBase polyScaledUp = scaleUpPoly(poly);
5220
pn = getActiveNodeType(layer, polyScaledUp, originalMerge, pn);
5221
NodeInst newNi = NodeInst.makeInstance(pn, ni.getAnchorCenter(), ni.getXSize(), ni.getYSize(),
5222
newCell, ni.getOrient(), null);
5226
// substract out layers
5227
layer = pn.getLayerIterator().next();
5228
for (NodeInst newNi : newNis) {
5229
Poly [] polys = tech.getShapeOfNode(newNi);
5230
for (Poly p : polys)
5232
if (p.getLayer() == layer)
5233
removePolyFromMerge(merge, layer, p);
5236
// add to map of created nodeinsts
5237
List<NodeInst> list = newNodes.get(layer);
5240
list = new ArrayList<NodeInst>();
5241
newNodes.put(layer, list);
5243
list.addAll(newNis);
5247
// now stitch new nodes together
5248
for (Layer layer : newNodes.keySet())
5250
Layer.Function fun = layer.getFunction();
5251
ArcProto ap = Generic.tech().universal_arc;
5252
if (fun.isPoly() || fun.isMetal() || fun.isDiff()) ap = arcsForLayer.get(layer);
5254
List<NodeInst> nodes = newNodes.get(layer);
5256
// check nodes against each other
5257
for (i=0; i<nodes.size(); i++)
5259
NodeInst ni1 = nodes.get(i);
5260
for (j=i+1; j<nodes.size(); j++)
5262
NodeInst ni2 = nodes.get(j);
5263
if (ni1 == ni2) continue;
5264
// see if shapes intersect. If so, connect them
5265
Poly poly1 = tech.getShapeOfNode(ni1)[0];
5266
Poly poly2 = tech.getShapeOfNode(ni2)[0];
5267
List<Line2D> overlappingEdges = new ArrayList<Line2D>();
5268
List<PolyBase> intersection = poly1.getIntersection(poly2, overlappingEdges);
5270
Point2D connectionPoint = null;
5271
if (intersection.size() > 0)
5273
// areas intersect, use center point of first common area
5274
PolyBase pint = intersection.get(0);
5275
connectionPoint = pint.getCenter();
5276
// round center point
5277
if (alignment != null)
5279
double x = connectionPoint.getX();
5280
double y = connectionPoint.getY();
5281
if (alignment.getWidth() > 0) x = Math.round(x/alignment.getWidth()) * alignment.getWidth();
5282
if (alignment.getHeight() > 0) y = Math.round(y/alignment.getHeight()) * alignment.getHeight();
5283
if (pint.contains(x, y))
5284
connectionPoint = new Point2D.Double(x, y);
5287
else if (overlappingEdges.size() > 0)
5289
// areas do not intersect, but share common edges. Use center point of first edge
5290
Line2D line = overlappingEdges.get(0);
5291
double x = (line.getX1()+line.getX2())/2.0;
5292
double y = (line.getY1()+line.getY2())/2.0;
5293
if (alignment != null) {
5294
double newx = x, newy = y;
5295
if ((line.getY1() == line.getY2()) && !isOnGrid(x, alignment.getWidth())) {
5296
newx = Math.round(x/alignment.getWidth()) * alignment.getWidth();
5298
if ((line.getX1() == line.getX2()) && !isOnGrid(y, alignment.getHeight())) {
5299
newy = Math.round(y/alignment.getHeight()) * alignment.getHeight();
5301
if (line.ptSegDist(newx, newy) == 0) {
5306
connectionPoint = new Point2D.Double(x, y);
5308
if (connectionPoint != null)
5310
// check on ap, we need to decide if diff arc is really diff arc or well arc
5311
// scale up poly so units match originalMerge units
5312
PolyBase poly1Scaled = scaleUpPoly(poly1);
5315
ap = findArcProtoForPoly(layer, poly1Scaled, originalMerge);
5317
if (ap == null) ap = Generic.tech().universal_arc;
5319
double width = ap.getDefaultLambdaBaseWidth();
5320
ArcProto arcProto = ap;
5321
if (arcProto != Generic.tech().universal_arc)
5323
// scale up to check merge
5324
Point2D connPointScaled = new Point2D.Double(scaleUp(connectionPoint.getX()), scaleUp(connectionPoint.getY()));
5325
Poly test1 = Poly.makeEndPointPoly(0.0, scaleUp(width), 0, connPointScaled, scaleUp(width/2.0), connPointScaled,
5326
scaleUp(width/2.0), Poly.Type.FILLED);
5327
// if on grid and merge contains, make arc
5328
if (isOnGrid(test1) && originalMerge.contains(layer, test1))
5330
realizeArc(arcProto, ni1.getOnlyPortInst(), ni2.getOnlyPortInst(), connectionPoint,
5331
connectionPoint, width, false, false, merge);
5334
arcProto = Generic.tech().universal_arc;
5336
//System.out.println("Using universal arc to connect "+ni1.describe(false)+" at "+connectionPoint+" to "+ni2.describe(false));
5338
realizeArc(arcProto, ni1.getOnlyPortInst(), ni2.getOnlyPortInst(), connectionPoint,
5339
connectionPoint, width, false, false, merge);
5346
private PrimitiveNode getActiveNodeType(Layer activeLayer, PolyBase poly, PolyMerge merge, PrimitiveNode defaultNode)
5348
if (unifyActive || ignoreActiveSelectWell) return defaultNode;
5349
if (defaultNode != pDiffNode && defaultNode != nDiffNode && defaultNode != diffNode) return defaultNode;
5351
if (activeLayer.getFunction() == Layer.Function.DIFFN) {
5352
// make sure n-diffusion is in n-select
5353
if (merge.contains(pSelectLayer, poly)) {
5354
// switch it pactive
5358
if (activeLayer.getFunction() == Layer.Function.DIFFP) {
5359
// make sure p-diffusion is in p-select
5360
if (merge.contains(nSelectLayer, poly)) {
5361
// switch it nactive
5368
private boolean isOnGrid(Poly poly)
5370
if (alignment != null)
5372
for (Point2D p : poly.getPoints())
5374
if (alignment.getWidth() > 0)
5375
if (!isOnGrid(p.getX(), alignment.getWidth())) return false;
5376
if (alignment.getHeight() > 0)
5377
if (!isOnGrid(p.getY(), alignment.getHeight())) return false;
5384
* Returns a new poly that is a scaled up version of the given poly
5385
* @param poly the poly
5386
* @return a new, scaled up poly
5388
private PolyBase scaleUpPoly(PolyBase poly) {
5389
Point2D [] points = new Point2D.Double[poly.getPoints().length];
5390
for(int p=0; p<points.length; p++)
5391
points[p] = new Point2D.Double(scaleUp(poly.getPoints()[p].getX()), scaleUp(poly.getPoints()[p].getY()));
5392
PolyBase newpoly = new PolyBase(points);
5393
newpoly.setStyle(poly.getStyle());
4060
5399
* Method to convert a Poly to one or more pure-layer nodes.
4061
5400
* @param poly the PolyBase to convert.
4062
5401
* @param cell the Cell in which to place the node.
5402
* @param originalMerge the original set of layers in the unextracted cell
4063
5403
* @return a List of NodeInsts that were created (null on error).
4065
private List<NodeInst> makePureLayerNodeFromPoly(PolyBase poly, Cell cell)
5405
private List<NodeInst> makePureLayerNodeFromPoly(PolyBase poly, Cell cell, PolyMerge originalMerge)
4067
5407
Layer layer = poly.getLayer();
4124
5464
for(PolyBase simplePoly : set)
4126
5466
Rectangle2D polyBounds = simplePoly.getBounds2D();
4127
double centerX = polyBounds.getCenterX() / SCALEFACTOR;
4128
double centerY = polyBounds.getCenterY() / SCALEFACTOR;
4129
Point2D center = new Point2D.Double(centerX, centerY);
4130
NodeInst ni = createNode(pNp, center, polyBounds.getWidth() / SCALEFACTOR,
4131
polyBounds.getHeight() / SCALEFACTOR, null, cell);
5467
NodeInst ni = makeAlignedPoly(polyBounds, layer, originalMerge, pNp, cell);
5468
if (ni == null) continue;
4132
5469
createdNodes.add(ni);
4134
5471
return createdNodes;
4136
5473
Rectangle2D polyBounds = poly.getBounds2D();
5474
NodeInst ni = makeAlignedPoly(polyBounds, layer, originalMerge, pNp, cell);
5476
createdNodes.add(ni);
5477
// double centerX = polyBounds.getCenterX() / SCALEFACTOR;
5478
// double centerY = polyBounds.getCenterY() / SCALEFACTOR;
5479
// Point2D center = new Point2D.Double(centerX, centerY);
5481
// // compute any trace information if the shape is nonmanhattan
5482
// EPoint [] newPoints = null;
5483
//// if (poly.getBox() == null)
5485
//// // store the trace
5486
//// Point2D [] points = poly.getPoints();
5487
//// newPoints = new EPoint[points.length];
5488
//// for(int i=0; i<points.length; i++)
5489
//// newPoints[i] = new EPoint(points[i].getX() / SCALEFACTOR, points[i].getY() / SCALEFACTOR);
5491
// NodeInst ni = createNode(pNp, center, polyBounds.getWidth() / SCALEFACTOR,
5492
// polyBounds.getHeight() / SCALEFACTOR, newPoints, cell);
5493
// createdNodes.add(ni);
5494
return createdNodes;
5497
private NodeInst makeAlignedPoly(Rectangle2D polyBounds, Layer layer, PolyMerge originalMerge, PrimitiveNode pNp, Cell cell)
4137
5499
double centerX = polyBounds.getCenterX() / SCALEFACTOR;
4138
5500
double centerY = polyBounds.getCenterY() / SCALEFACTOR;
5501
double width = polyBounds.getWidth() / SCALEFACTOR;
5502
double height = polyBounds.getHeight() / SCALEFACTOR;
5503
if (alignment != null)
5505
if (alignment.getWidth() > 0)
5507
// centers can be offgrid, only edges matter
5508
double aliX = Math.round(centerX / (alignment.getWidth()/2)) * (alignment.getWidth()/2);
5509
if (aliX != centerX)
5511
double newWidth = width + Math.abs(aliX-centerX)*2;
5512
Poly rectPoly = new Poly(scaleUp(aliX), scaleUp(centerY), scaleUp(newWidth), scaleUp(height));
5513
if (!originalMerge.contains(layer, rectPoly))
5515
if (aliX > centerX) aliX -= alignment.getWidth(); else
5516
aliX += alignment.getWidth();
5517
newWidth = width + Math.abs(aliX-centerX)*2;
5518
rectPoly = new Poly(scaleUp(aliX), scaleUp(centerY), scaleUp(newWidth), scaleUp(height));
5519
if (!originalMerge.contains(layer, rectPoly)) return null;
5525
if (alignment.getHeight() > 0)
5527
// centers can be offgrid, only edges matter
5528
double aliY = Math.round(centerY / (alignment.getHeight()/2)) * (alignment.getHeight()/2);
5529
if (aliY != centerY)
5531
double newHeight = height + Math.abs(aliY-centerY)*2;
5532
Poly rectPoly = new Poly(scaleUp(centerX), scaleUp(aliY), scaleUp(width), scaleUp(newHeight));
5533
if (!originalMerge.contains(layer, rectPoly))
5535
if (aliY > centerY) aliY -= alignment.getHeight(); else
5536
aliY += alignment.getHeight();
5537
newHeight = height + Math.abs(aliY-centerY)*2;
5538
rectPoly = new Poly(scaleUp(centerX), scaleUp(aliY), scaleUp(width), scaleUp(newHeight));
5539
if (!originalMerge.contains(layer, rectPoly)) return null;
4139
5546
Point2D center = new Point2D.Double(centerX, centerY);
4141
// compute any trace information if the shape is nonmanhattan
4142
EPoint [] newPoints = null;
4143
// if (poly.getBox() == null)
4145
// // store the trace
4146
// Point2D [] points = poly.getPoints();
4147
// newPoints = new EPoint[points.length];
4148
// for(int i=0; i<points.length; i++)
4149
// newPoints[i] = new EPoint(points[i].getX() / SCALEFACTOR, points[i].getY() / SCALEFACTOR);
4151
NodeInst ni = createNode(pNp, center, polyBounds.getWidth() / SCALEFACTOR,
4152
polyBounds.getHeight() / SCALEFACTOR, newPoints, cell);
4153
createdNodes.add(ni);
4154
return createdNodes;
5547
NodeInst ni = createNode(pNp, center, width, height, null, cell);
4158
5552
* Method to clean-up exports.
5553
* @param oldCell the original cell (unextracted)
5554
* @param newCell the new cell
4160
5556
private void cleanupExports(Cell oldCell, Cell newCell)
4162
5558
// first restore original exports (which were on pure-layer nodes and must now be placed back)
4163
5559
for(Export e : exportsToRestore)
4165
EPoint loc = e.getOriginalPort().getPoly().getCenter();
5561
EPoint loc = e.getPoly().getCenter();
4166
5562
boolean found = false;
4167
5563
Rectangle2D bounds = new Rectangle2D.Double(loc.getX(), loc.getY(), 0, 0);
4168
5564
for(Iterator<RTBounds> it = newCell.searchIterator(bounds); it.hasNext(); )