~ubuntu-branches/ubuntu/wily/electric/wily-proposed

« back to all changes in this revision

Viewing changes to com/sun/electric/tool/routing/seaOfGates/SeaOfGatesEngine.java

  • Committer: Package Import Robot
  • Author(s): Markus Koschany
  • Date: 2015-08-12 13:15:54 UTC
  • mfrom: (1.2.7)
  • Revision ID: package-import@ubuntu.com-20150812131554-k4amekjrk0qw6cju
Tags: 9.06+dfsg-1
* Imported Upstream version 9.06+dfsg.
* Use --download-current-version for get-orig-source target.
* Declare compliance with Debian Policy 3.9.6.
* Vcs-Browser field: Switch to cgit.
* debian/control: Add all build-dependencies only to Build-Depends.
* Install ElectricIcon64x64.png icon. Drop debian/icons directory.
  Convert ElectricIcon64x64.png with imagemagick to electric.xpm at
  build-time.
* Update copyright years.

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
import com.sun.electric.database.geometry.Poly;
32
32
import com.sun.electric.database.geometry.PolyBase;
33
33
import com.sun.electric.database.geometry.PolyBase.Point;
 
34
import com.sun.electric.database.geometry.PolyMerge;
34
35
import com.sun.electric.database.hierarchy.Cell;
35
36
import com.sun.electric.database.hierarchy.Export;
36
37
import com.sun.electric.database.id.ArcProtoId;
42
43
import com.sun.electric.database.prototype.NodeProto;
43
44
import com.sun.electric.database.prototype.PortProto;
44
45
import com.sun.electric.database.text.Name;
 
46
import com.sun.electric.database.text.TextUtils;
45
47
import com.sun.electric.database.topology.ArcInst;
46
48
import com.sun.electric.database.topology.Connection;
47
49
import com.sun.electric.database.topology.Geometric;
59
61
import com.sun.electric.technology.PrimitiveNode;
60
62
import com.sun.electric.technology.SizeOffset;
61
63
import com.sun.electric.technology.Technology;
 
64
import com.sun.electric.technology.Technology.NodeLayer;
62
65
import com.sun.electric.technology.technologies.Generic;
 
66
import com.sun.electric.tool.Job;
63
67
import com.sun.electric.tool.drc.DRC;
64
68
import com.sun.electric.tool.routing.SeaOfGates;
65
69
import com.sun.electric.tool.routing.SeaOfGates.SeaOfGatesArcProperties;
66
70
import com.sun.electric.tool.routing.SeaOfGates.SeaOfGatesCellParameters;
 
71
import com.sun.electric.tool.routing.SeaOfGates.SeaOfGatesExtraBlockage;
 
72
import com.sun.electric.tool.routing.SeaOfGates.SeaOfGatesTrack;
67
73
import com.sun.electric.tool.user.ErrorLogger;
 
74
import com.sun.electric.tool.user.ErrorLogger.MessageLog;
68
75
import com.sun.electric.tool.user.ui.RoutingDebug;
69
76
import com.sun.electric.util.ElapseTimer;
70
 
import com.sun.electric.util.TextUtils;
71
77
import com.sun.electric.util.math.DBMath;
72
78
import com.sun.electric.util.math.FixpCoord;
73
79
import com.sun.electric.util.math.FixpRectangle;
123
129
 * Things to do:
124
130
 *  Fix ability to route to any point on destination (ANYPOINTONDESTINATION=true)
125
131
 *  Improve Global routing
126
 
 *  Ability to route to any SearchVertex in opposing direction
127
132
 *  Weight layer changes higher if far from end layer and going away
128
133
 *  Detect "river routes" and route specially
129
134
 *  Rip-up
131
136
 */
132
137
public abstract class SeaOfGatesEngine
133
138
{
134
 
        public static final boolean DEBUGGRIDDING = false;
135
 
        public static final boolean NEWBLOCKAGE = true;
 
139
        // code switches
 
140
        /** true to run both directions and choose best */                      private static final boolean CHECKBOTHDIRECTIONS = false;
 
141
        /** true to use new minimum area detection */                           private static final boolean MINAREACHECK = true;
 
142
        /** true to use new via spacing calculation */                          private static final boolean NEWVIACALC = true;
 
143
        /** true to ignore grid errors at start of route */                     private static final boolean NOGRIDPENALTYATSOURCE = true;
136
144
        /** true to route to any point on the destination */            private static final boolean ANYPOINTONDESTINATION = true;
137
 
        /** true to stick to destination edge */                                        private static final boolean STICKTOJUMPEDGES = false;
 
145
 
 
146
        // tunable parameters
 
147
        /** Granularity of coordinates. */                                                      private static final double GRAINSIZE = 1;
138
148
        /** the height/width ratio that defines a spine */                      private static final double SPINERATIO = 50;
139
 
 
140
 
        /** Granularity of coordinates. */                                                      private static final double GRAINSIZE = 1;
141
149
        /** Cost: of forcing horizontal/vertical metal layers */        private static final int COSTALTERNATINGMETAL = 20;
142
150
        /** Cost of changing layers. */                                                         private static final int COSTLAYERCHANGE = 8;
143
151
        /** Cost of routing away from the target. */                            private static final int COSTWRONGDIRECTION = 15;
145
153
        /** Cost of making a turn. */                                                           private static final int COSTTURNING = 1;
146
154
        /** Cost of having coordinates that are off-grid. */            private static final int COSTOFFGRID = 15;
147
155
 
148
 
        /** Bit set in network ID for virtual blockage. */                      private static final int OFFSETVIRTUAL = 1;
149
 
        /** Bit set in network ID for blockage on end A. */                     private static final int OFFSETENDA = 2;
150
 
        /** Bit set in network ID for blockage on end B. */                     private static final int OFFSETENDB = 4;
 
156
        // blockage factors
 
157
        /** Bit set in network ID for fake endpoint blockage. */        private static final int BLOCKAGEFAKEENDPOINT = 1;
 
158
        /** Bit set in network ID for blockage on end A. */                     private static final int BLOCKAGEENDA = 2;
 
159
        /** Bit set in network ID for blockage on end B. */                     private static final int BLOCKAGEENDB = 4;
 
160
        /** Bit set in network ID for user-supplied blockage. */        private static final int BLOCKAGEFAKEUSERSUPPLIED = 8;
 
161
        /** Number of bits to shift to skip blockage bits */            private static final int SHIFTBLOCKBITS = 4;
151
162
 
152
 
        public static SearchVertex svAborted = new SearchVertex(0, 0, 0, 0, null, null, 0, null);
153
 
        public static SearchVertex svExhausted = new SearchVertex(0, 0, 0, 0, null, null, 0, null);
154
 
        public static SearchVertex svLimited = new SearchVertex(0, 0, 0, 0, null, null, 0, null);
155
 
        public static SearchVertex svAbandoned = new SearchVertex(0, 0, 0, 0, null, null, 0, null);
 
163
        public static SearchVertex svAborted = new SearchVertex(0, 0, 0, 0, 0, null, null, 0, null, 0);
 
164
        public static SearchVertex svExhausted = new SearchVertex(0, 0, 0, 0, 0, null, null, 0, null, 0);
 
165
        public static SearchVertex svLimited = new SearchVertex(0, 0, 0, 0, 0, null, null, 0, null, 0);
 
166
        public static SearchVertex svAbandoned = new SearchVertex(0, 0, 0, 0, 0, null, null, 0, null, 0);
156
167
 
157
168
        /** number of metal layers in the technology. */                        private static int numMetalLayers;
158
169
 
159
 
        /** Environment */                                          protected Environment env;
 
170
        /** Environment */                                          private Environment env;
160
171
        /** Cell in which routing occurs. */                                            private Cell cell;
161
172
        /** true to run to/from and from/to routing in parallel */      private boolean parallelDij;
162
173
        /** for logging errors */                                                                       private ErrorLogger errorLogger;
163
174
        /** Cell size. */                                                                                       private Rectangle2D cellBounds;
 
175
        /** Cell-wide routing limit */                                                          private ERectangle routingBoundsLimit;
164
176
        /** Technology to use for routing. */                                           private Technology tech;
165
 
        /** metal layers in the technology. */                                          private Layer[] metalLayers;
 
177
        /** metal layers in the technology. */                                          private Layer[][] metalLayers;
 
178
        /** single layer to use for each metal level. */                        private Layer[] primaryMetalLayer;
166
179
        /** via layers in the technology. */                                            private Layer[] viaLayers;
167
 
        /** arcs to use for each metal layer. */                                        private ArcProto[] metalArcs;
 
180
        /** layer that removes metal in the technology. */                      private Map<Layer,Layer> removeLayers;
 
181
        /** arcs to use for each metal layer. */                                        private ArcProto[][] metalArcs;
 
182
        /** pure-layer nodes to use for each metal layer. */            private PrimitiveNode[][] metalPureLayerNodes;
 
183
        /** single arc to use for each metal layer. */                          private ArcProto[] primaryMetalArc;
 
184
        /** maximum default arc width. */                                                       private double[] maxDefArcWidth;
 
185
        /** minimum area for a layer. */                                                        private double[] minimumArea;
 
186
        /** minimum resolution for technology. */                                       private double minResolution;
 
187
        /** size of 2X arcs. */                                                                         private double[] size2X;
 
188
        /** maximum length of tapers. */                                                        private double[] taperLength;
168
189
        /** favoritism for each metal layer. */                                         private boolean[] favorArcs;
169
190
        /** avoidance for each metal layer. */                                          private boolean[] preventArcs;
170
 
        /** vias to use to go up from each metal layer. */                      private MetalVias[] metalVias;
171
 
        /** metal gridding for the cell. */                                                     private double[][] metalGrid;
 
191
        /** arcs that can only be tapers. */                                            private boolean[] taperOnlyArcs;
 
192
        /** vias to use to go up from each metal layer. */                      private MetalVias[] metalVias, metalVias2X;
 
193
        /** metal gridding for the cell. */                                                     private SeaOfGatesTrack[][] metalGrid;
172
194
        /** metal gridding range for the cell. */                                       private double[] metalGridRange;
173
 
        /** maximum possible DRC surround around the metal. */      private double[] metalSurround;
174
 
        /** worst spacing rule for a given metal layer. */                      private double[] worstMetalSurround;
175
 
        /** minimum spacing between the centers of two vias. */         private double[] viaSurround;
 
195
        /** spacing rules for a given metal layer. */                           private double[] metalSurroundX, metalSurroundY;
 
196
        /** minimum spacing between the corners of two vias. */         private double[] viaSurround;
 
197
        /** minimum size of two vias. */                                                        private double[] viaSize;
176
198
        /** R-Trees for routing blockages */                                            private BlockageTrees rTrees;
177
199
        /** converts Networks to unique integers */                                     private Map<Network, Integer> netIDs;
178
200
        /** preferences */                                                                                      private SeaOfGates.SeaOfGatesOptions prefs;
179
 
        /** interaction with outer environment */                   public Handler handler;
 
201
        /** interaction with outer environment */                   private Handler handler;
180
202
        /** EditingPreferences */                                   private EditingPreferences ep;
181
203
        /** cell-specific parameters */                                                         private SeaOfGatesCellParameters sogp;
182
204
        /** taps that need to be added to spine routes */                       private List<NeededRoute> tapRoutes;
184
206
        /** total number of blockages to node-extract */                        private int totalBlockages;
185
207
        /** number of blockages node-extracted so far */                        private int blockagesFound;
186
208
        /** minimum spacing between this metal and itself. */           private Map<Double, Map<Double, double[]>>[] layerSurround;
187
 
        /** the total length of routing */                                                      private double totalWireLength;
 
209
        /** routing quality */                                                                          private SoGWireQualityMetric sogQual;
188
210
 
189
211
        /************************************** CONTROL **************************************/
190
212
 
218
240
        public void routeIt(Handler handler, Cell cell, boolean quiet, List<ArcInst> arcsToRoute, SeaOfGatesCellParameters sogp)
219
241
        {
220
242
                messagesQuiet = quiet;
221
 
                totalWireLength = 0;
222
243
                // initialize routing
223
244
                this.handler = handler;
224
245
                ep = handler.getEditingPreferences();
230
251
                cellBounds = cell.getBounds();
231
252
                tech = cell.getTechnology();
232
253
 
 
254
                // find the routing bounds limit
 
255
                routingBoundsLimit = null;
 
256
                String routingBoundsLayerName = sogp.getRoutingBoundsLayerName();
 
257
                if (routingBoundsLayerName != null)
 
258
                {
 
259
                        Layer boundsLayer = tech.findLayer(routingBoundsLayerName);
 
260
                        if (boundsLayer == null)
 
261
                        {
 
262
                                System.out.println("WARNING: Routing bounds layer '" + routingBoundsLayerName + "' not found in technology " + tech.getTechName());
 
263
                        } else
 
264
                        {
 
265
                                List<NodeInst> boundsLayerNodes = new ArrayList<NodeInst>();
 
266
                                for(Iterator<NodeInst> it = cell.getNodes(); it.hasNext(); )
 
267
                                {
 
268
                                        NodeInst ni = it.next();
 
269
                                        if (ni.isCellInstance()) continue;
 
270
                                        if (ni.getFunction() != PrimitiveNode.Function.NODE) continue;
 
271
                                        PrimitiveNode pNp = (PrimitiveNode)ni.getProto();
 
272
                                        NodeLayer[] nodeLayers = pNp.getNodeLayers();
 
273
                                        for(int i=0; i<nodeLayers.length; i++)
 
274
                                        {
 
275
                                                if (nodeLayers[i].getLayer() == boundsLayer)
 
276
                                                {
 
277
                                                        boundsLayerNodes.add(ni);
 
278
                                                        break;
 
279
                                                }
 
280
                                        }
 
281
                                }
 
282
                                if (boundsLayerNodes.size() == 0)
 
283
                                {
 
284
                                        System.out.println("WARNING: No nodes found with the routing bounds layer '" + routingBoundsLayerName + "'");
 
285
                                } else if (boundsLayerNodes.size() > 1)
 
286
                                {
 
287
                                        System.out.println("WARNING: Found " + boundsLayerNodes.size() + " nodes with the routing bounds layer, must have only 1.");
 
288
                                } else
 
289
                                {
 
290
                                        NodeInst ni = boundsLayerNodes.get(0);
 
291
                                        routingBoundsLimit = ni.getBounds();
 
292
                                        System.out.println("NOTE: No routes will extend beyond " + TextUtils.formatDistance(routingBoundsLimit.getMinX()) +
 
293
                                                "<=X<=" + TextUtils.formatDistance(routingBoundsLimit.getMaxX()) + " AND " +
 
294
                                                TextUtils.formatDistance(routingBoundsLimit.getMinY()) + "<=Y<=" +
 
295
                                                TextUtils.formatDistance(routingBoundsLimit.getMaxY()));
 
296
                                }
 
297
                        }
 
298
                }
 
299
 
233
300
                if (initializeDesignRules()) return;
234
301
                initializeGrids();
235
302
                netIDs = new HashMap<Network, Integer>();
238
305
                Netlist netList = cell.getNetlist();
239
306
 
240
307
                // get arcs to route
241
 
                Set<String> netsToRoute = sogp.getNetsToRoute();
 
308
                List<String> netsToRoute = sogp.getNetsToRoute();
242
309
                if (netsToRoute != null && netsToRoute.size() > 0)
243
310
                {
244
311
                        // overriding nets are listed in the Sea-of-Gates Cell Properties, see if the user selected an overriding subset
268
335
                                        for(Iterator<ArcInst> it = net.getArcs(); it.hasNext() ;)
269
336
                                        {
270
337
                                                ai = it.next();
 
338
                                                if (ai.getProto() != Generic.tech().unrouted_arc) continue;
271
339
                                                arcsToRoute.add(ai);
272
340
                                        }
273
341
                                }
307
375
                info("Sea-of-gates router finding " + allRoutes.size() + " paths on " + routeBatches.length + " networks in cell " + cell.describe(false));
308
376
                if (hadNonmanhattan.booleanValue())
309
377
                {
310
 
                        String info = "Found nonmanhattan geometry. This will cause large rectangular blockages, which may block too much.";
311
 
                        warn(info);
312
 
                        errorLogger.logMessageWithLines(info, linesInNonMahnattan, linesInNonMahnattan, cell, 0, false);
 
378
                        String info = "Found nonmanhattan geometry (" + linesInNonMahnattan.size() + " points). This may cause larger rectangular blockages, which may block too much.";
 
379
                        if (linesInNonMahnattan.size() > 100)
 
380
                        {
 
381
                                linesInNonMahnattan = linesInNonMahnattan.subList(0, 100); // just show first 100
 
382
                                info += ". Displaying only the first 100";
 
383
                        }
 
384
                        warn(info, cell, linesInNonMahnattan, null);
313
385
                }
314
386
 
315
387
                // do "global routing" preprocessing
332
404
                                        if (arcsInCell.contains(ai)) continue;
333
405
                                        Network net = netList.getNetwork(ai, 0);
334
406
                                        RouteBatch rb = additionalRBs.get(net);
335
 
                                        if (rb == null) additionalRBs.put(net, rb = new RouteBatch());
 
407
                                        if (rb == null) additionalRBs.put(net, rb = new RouteBatch(net.getName()));
336
408
 
337
409
                                        // get Arc information about the ends of the path
338
410
                                        PortInst aPi = ai.getHeadPortInst();
352
424
                        }
353
425
 
354
426
                        // do the global routing
355
 
                        double wirePitch = metalSurround[0] + metalArcs[0].getDefaultLambdaBaseWidth(ep);
 
427
                        double wirePitch = Math.max(metalSurroundX[0], metalSurroundY[0]) + maxDefArcWidth[0];
356
428
                        GlobalRouter gr = doGlobalRouting(cell, routeBatches, fakeRBs, wirePitch);
357
429
 
358
430
                        // reorder so that paths without Global Routing (small ones) come first
383
455
                        setProgressNote("Route " + allRoutes.size() + " paths...");
384
456
                        info("Routing " + allRoutes.size() + " paths...");
385
457
                }
 
458
 
 
459
                // warn if an endpoint is off-grid and gridding is forced
386
460
                for(NeededRoute nr : allRoutes)
387
 
                {
388
 
                        if (nr.spineTaps != null) nr.routeName += " (spine)"; else
389
 
                        {
390
 
                                if (nr.batch.routesInBatch.size() > 1)
391
 
                                        nr.routeName += " (" + (nr.routeInBatch+1) + " of " + nr.batch.routesInBatch.size() + ")";
392
 
                        }
393
 
                }
 
461
                        nr.checkGridValidity();
394
462
 
395
463
                // if debugging, stop now
396
464
                if (RoutingDebug.isActive() && allRoutes.size() > 0)
397
465
                {
398
 
                        int whichRoute = RoutingDebug.getDesiredRouteToDebug();
399
 
                        if (whichRoute < 0) whichRoute = 0;
400
 
                        if (whichRoute >= allRoutes.size()) whichRoute = allRoutes.size() - 1;
401
 
                        NeededRoute nr = allRoutes.get(whichRoute);
402
 
 
403
 
                        if (RoutingDebug.isDisplayAreaBlockages())
404
 
                        {
405
 
                                RoutingDebug.showGeometryInArea(nr);
406
 
                                return;
407
 
                        }
408
 
                        if (RoutingDebug.isDisplayEndBlockages())
409
 
                        {
410
 
                                RoutingDebug.showGeometryAtRouteEnds(nr);
411
 
                                return;
412
 
                        }
413
 
                        if (RoutingDebug.isTestRoutingGrid())
414
 
                        {
415
 
                                RoutingDebug.showRoutingGrid(nr);
416
 
                                return;
417
 
                        }
418
 
                        if (RoutingDebug.isDisplayRouting())
419
 
                        {
420
 
                                RoutingDebug.debugRoute(nr, allRoutes);
421
 
                                return;
 
466
                        String whichRoute = RoutingDebug.getDesiredRouteToDebug();
 
467
                        if (whichRoute != null)
 
468
                        {
 
469
                                NeededRoute nr = allRoutes.get(0);
 
470
                                for(NeededRoute nrTest : allRoutes)
 
471
                                {
 
472
                                        if (nrTest.routeName.equalsIgnoreCase(whichRoute))
 
473
                                        {
 
474
                                                nr = nrTest;
 
475
                                                break;
 
476
                                        }
 
477
                                }
 
478
                                nr.setDebugging(Boolean.valueOf(RoutingDebug.isEndADebugging()));
422
479
                        }
423
480
                }
424
481
 
457
514
                // do the routing
458
515
                if (numberOfThreads > 1) doRoutingParallel(numberOfThreads, allRoutes); else
459
516
                        doRouting(allRoutes);
460
 
                handler.flush(true);
461
 
 
462
 
                if (tapRoutes.size() > 0)
463
 
                {
464
 
                        setProgressNote("Adding taps to spine routes...");
465
 
                        info("------------------ Adding taps to spine routes...");
466
 
 
467
 
                        // do the routing again
468
 
                        if (numberOfThreads > 1) doRoutingParallel(numberOfThreads, tapRoutes); else
469
 
                                doRouting(tapRoutes);
470
 
                        handler.flush(true);
471
 
                }
472
 
 
473
 
                // see if any routes failed and need to be redone
474
 
                List<NeededRoute> redoRoutes = new ArrayList<NeededRoute>();
475
 
                for (int b = 0; b < routeBatches.length; b++)
476
 
                {
477
 
                        for(NeededRoute nr : routeBatches[b].routesInBatch)
478
 
                        {
479
 
                                if (nr.routedSuccess) continue;
480
 
                                redoRoutes.add(nr);
481
 
                                nr.buckets = null;
482
 
                                nr.errorMessage = null;
483
 
                                nr.complexityLimit = prefs.rerunComplexityLimit;
484
 
                                nr.makeWavefronts();
485
 
                        }
486
 
                }
487
 
 
488
 
                // redo the routing on the failed routes, ignoring global routing information
489
 
                if (prefs.reRunFailedRoutes && redoRoutes.size() > 0)
490
 
                {
491
 
                        setProgressNote("Re-Route " + redoRoutes.size() + " paths...");
492
 
                        info("------------------ Re-Route " + redoRoutes.size() + " paths...");
493
 
 
494
 
                        // do the routing again
495
 
                        for(NeededRoute nr : redoRoutes) nr.reroute = true;
496
 
                        if (numberOfThreads > 1) doRoutingParallel(numberOfThreads, redoRoutes); else
497
 
                                doRouting(redoRoutes);
498
 
                        handler.flush(true);
499
 
                }
500
 
 
501
 
                // make new unrouted arcs for all failed routes
502
 
                RouteResolution resolution = new RouteResolution(cell.getId());
503
 
                for (int b = 0; b < routeBatches.length; b++)
504
 
                {
505
 
                        for(NeededRoute nr : routeBatches[b].routesInBatch)
506
 
                        {
507
 
                                if (nr.routedSuccess) continue;
508
 
                                resolution.addUnrouted(nr.aPi, nr.bPi);
509
 
                        }
510
 
                }
511
 
                if (!DEBUGGRIDDING)
 
517
                if (!RoutingDebug.isActive())
 
518
                {
 
519
                        handler.flush(true);
 
520
 
 
521
                        if (tapRoutes.size() > 0)
 
522
                        {
 
523
                                setProgressNote("Adding taps to spine routes...");
 
524
                                info("------------------ Adding taps to spine routes...");
 
525
        
 
526
                                // do the routing again
 
527
                                if (numberOfThreads > 1) doRoutingParallel(numberOfThreads, tapRoutes); else
 
528
                                        doRouting(tapRoutes);
 
529
                                handler.flush(true);
 
530
                        }
 
531
 
 
532
                        // see if any routes failed and need to be redone
 
533
                        List<NeededRoute> redoRoutes = new ArrayList<NeededRoute>();
 
534
                        for (int b = 0; b < routeBatches.length; b++)
 
535
                        {
 
536
                                for(NeededRoute nr : routeBatches[b].routesInBatch)
 
537
                                {
 
538
                                        if (nr.routedSuccess) continue;
 
539
                                        redoRoutes.add(nr);
 
540
                                        nr.buckets = null;
 
541
                                        nr.errorMessage = null;
 
542
                                        nr.complexityLimit = prefs.rerunComplexityLimit;
 
543
                                        nr.makeWavefronts();
 
544
                                }
 
545
                        }
 
546
 
 
547
                        // redo the routing on the failed routes, ignoring global routing information
 
548
                        if (prefs.reRunFailedRoutes && redoRoutes.size() > 0)
 
549
                        {
 
550
                                setProgressNote("Re-Route " + redoRoutes.size() + " paths...");
 
551
                                info("------------------ Re-Route " + redoRoutes.size() + " paths...");
 
552
 
 
553
                                // do the routing again
 
554
                                for(NeededRoute nr : redoRoutes)
 
555
                                {
 
556
                                        nr.reroute = true;
 
557
 
 
558
                                        // if an error was already logged for this route, remove it
 
559
                                        if (nr.loggedMessage != null)
 
560
                                        {
 
561
                                                List<MessageLog> oldMessage = new ArrayList<MessageLog>();
 
562
                                                oldMessage.add(nr.loggedMessage);
 
563
                                                errorLogger.deleteMessages(oldMessage);
 
564
                                        }
 
565
                                }
 
566
                                
 
567
                                if (numberOfThreads > 1) doRoutingParallel(numberOfThreads, redoRoutes); else
 
568
                                        doRouting(redoRoutes);
 
569
                                handler.flush(true);
 
570
                        }
 
571
 
 
572
                        // make new unrouted arcs for all failed routes
 
573
                        RouteResolution resolution = new RouteResolution(cell.getId());
 
574
                        for (int b = 0; b < routeBatches.length; b++)
 
575
                        {
 
576
                                for(NeededRoute nr : routeBatches[b].routesInBatch)
 
577
                                {
 
578
                                        if (nr.routedSuccess) continue;
 
579
                                        resolution.addUnrouted(nr.aPi, nr.bPi, nr.getName());
 
580
                                }
 
581
                        }
512
582
                        handler.instantiate(resolution);
513
 
                handler.flush(true);
514
 
 
515
 
                // show statistics on the routing
516
 
                summarize(routeBatches, allRoutes);
517
 
                // dumpSpacing();
518
 
 
 
583
                        handler.flush(true);
 
584
 
 
585
                        // show statistics on the routing
 
586
                        summarize(routeBatches, allRoutes);
 
587
                        // dumpSpacing();
 
588
                }
 
589
                
519
590
                // clean up
520
591
                handler.termLogging(errorLogger);
521
592
                handler.stopProgressDialog();
551
622
 
552
623
                        // now add new Unrouted arcs from the Steiner tree calculations
553
624
                        for(NeededRoute nr : rb.routesInBatch)
554
 
                                res.addUnrouted(nr.aPi, nr.bPi);
 
625
                                res.addUnrouted(nr.aPi, nr.bPi, nr.getName());
555
626
                        handler.instantiate(res);
556
627
                }
557
628
                handler.flush(true);
564
635
         */
565
636
        private void summarize(RouteBatch[] routeBatches, List<NeededRoute> allRoutes)
566
637
        {
567
 
                int numRoutedSegments = 0;
568
 
                int numFailedNets = 0;
569
 
                int numFailedBatches = 0;
 
638
                // calculate metrics only if routing results are not stored in special cell
 
639
                // otherwise the result cell doesn't have any connectivity
 
640
                sogQual = new SoGWireQualityMetric("SoG");
 
641
                sogQual.setOutput(prefs.qualityPrintStream);
570
642
                for (int b = 0; b < routeBatches.length; b++)
571
643
                {
572
 
                        boolean failed = false;
573
 
                        for(NeededRoute nr : routeBatches[b].routesInBatch)
574
 
                        {
575
 
                                if (nr.routedSuccess)
576
 
                                {
577
 
                                        numRoutedSegments++;
578
 
                                } else
579
 
                                {
580
 
                                        if (nr.errorMessage != null)
581
 
                                        {
582
 
                                                failed = true;
583
 
                                                numFailedNets++;
584
 
                                        }
585
 
                                }
586
 
                        }
587
 
                        if (failed) numFailedBatches++;
 
644
                        sogQual.calculate(routeBatches[b]);
588
645
                }
589
646
                prefs.theTimer.end();
590
 
                info("Cell " + cell.describe(false) + " routed " + numRoutedSegments + " out of " + allRoutes.size() +
591
 
                        " segments; total length of routed wires is " + formatDistance(totalWireLength) +
 
647
                info("Cell " + cell.describe(false) + " routed " + sogQual.numRoutedSegments + " out of " + allRoutes.size() +
 
648
                        " segments" +
592
649
                        " (took " + prefs.theTimer + ")");
593
 
                if (numFailedNets > 0) info("NOTE: " + numFailedNets + " segments on " + numFailedBatches + " nets were not routed");
 
650
                if (sogQual.numFailedSegments > 0) info("NOTE: " + sogQual.numFailedSegments + " segments on " + sogQual.numFailedBatches + " nets were not routed");
 
651
 
 
652
                info(sogQual.printAverageResults());
 
653
        }
 
654
        
 
655
        public String getRoutedNetRatio()
 
656
        {
 
657
                String value = "";
 
658
                if (sogQual != null)
 
659
                {
 
660
                        int total = sogQual.numFailedSegments + sogQual.numRoutedSegments;
 
661
                        value = "" + sogQual.numRoutedSegments + "/" + total;
 
662
                }
 
663
                return value;
594
664
        }
595
665
 
596
666
        /**
618
688
        public int getNumMetals() { return numMetalLayers; }
619
689
 
620
690
        /**
621
 
         * Method to return the metal Layer associated with a layer number.
 
691
         * Method to return the primary metal Layer associated with a layer number.
622
692
         * @param layNum a layer number, from 0 to getNumMetals()-1.
623
693
         * @return the metal Layer being used on the layer number.
624
694
         */
625
 
        public Layer getMetalLayer(int layNum) { return metalLayers[layNum]; }
 
695
        public Layer getPrimaryMetalLayer(int layNum) { return primaryMetalLayer[layNum]; }
 
696
 
 
697
        private boolean isOnMetalArc(int layNum, ArcProto ap)
 
698
        {
 
699
                for(int c=0; c<metalArcs[layNum].length; c++)
 
700
                        if (metalArcs[layNum][c] == ap) return true;
 
701
                return false;
 
702
        }
626
703
 
627
704
        /**
628
705
         * Method to return the via Layer associated with a layer number.
632
709
        public Layer getViaLayer(int layNum) { return viaLayers[layNum]; }
633
710
 
634
711
        /**
635
 
         * Method to convert a distance to a string, using scale from the technology considered in routing.
636
 
         * See com.sun.electric.util.TextUtils#formatDistance(double, Technology)
637
 
         * @param v the distance value to format.
638
 
         * @return the string representation of the number.
639
 
         */
640
 
        protected String formatDistance(double v) {
641
 
                return com.sun.electric.database.text.TextUtils.formatDistance(v, tech);
642
 
        }
643
 
 
644
 
        /**
645
712
         * Method to describe this NodeInst as a string.
646
713
         * @param ni NodeInst to describe
647
714
         * @return a description of this NodeInst as a string.
693
760
                return libDescribe ? ap.getFullName() : ap.getName();
694
761
        }
695
762
 
 
763
        protected Environment getEnvironment() { return env; }
 
764
 
696
765
        /**
697
766
         * Check if we are scheduled to abort. If so, print message if non null and
698
767
         * return true.
740
809
        }
741
810
 
742
811
        /**
 
812
         * Log a message at the WARN level including
 
813
         * ErrorLogger
 
814
         * @param msg the message string to be logged
 
815
         * @param cell cell warning belongs to
 
816
         * @param linesToShow list of points related to the warning
 
817
         * @param polysToShow list of polygons related to the warning
 
818
         */
 
819
        protected void warn(String msg, Cell cell, List<EPoint> linesToShow, List<PolyBase> polysToShow)
 
820
        {
 
821
                warn(msg);
 
822
                if (polysToShow != null)
 
823
                {
 
824
                        errorLogger.logMessage(msg, null, polysToShow, cell, 0, false);
 
825
                        return;
 
826
                }
 
827
                errorLogger.logMessageWithLines(msg, linesToShow, linesToShow, cell, 0, false);
 
828
        }
 
829
 
 
830
        /**
743
831
         * Log a message at the ERROR level.
744
832
         *
745
833
         * @param msg the message string to be logged
799
887
                        // get information on the segment to be routed
800
888
                        NeededRoute nr = allRoutes.get(r);
801
889
                        setProgressValue(r, totalRoutes);
802
 
                        setProgressNote("Network " + nr.routeName);
803
 
                        if (!messagesQuiet)
804
 
                                trace("Routing network " + nr.routeName + "...");
 
890
                        String progMsg = "Routing network " + nr.routeName + "...";
 
891
                        setProgressNote(progMsg);
 
892
                        if (!messagesQuiet && !Job.getDebug()) trace(progMsg);
 
893
 
 
894
                        if (nr.alreadyRouted)
 
895
                        {
 
896
                                // show the existing route
 
897
                                List<PolyBase> polysInConnection = new ArrayList<PolyBase>();
 
898
                                Point[] points = new Point[2];
 
899
                                points[0] = PolyBase.fromLambda(nr.aX, nr.aY);
 
900
                                points[1] = PolyBase.fromLambda(nr.bX, nr.bY);
 
901
                                polysInConnection.add(new PolyBase(points));
 
902
                                for(int i=0; i<numMetalLayers; i++)
 
903
                                {
 
904
                                        RTNode<SOGBound> root = rTrees.metalTrees[i].getRoot();
 
905
                                        if (root != null) addNetsToList(root, nr.netID, polysInConnection);
 
906
                                }
 
907
 
 
908
                                if (prefs.runOnConnectedRoutes)
 
909
                                {
 
910
                                        warn("Network " + nr.getName() + " is already routed in the circuit, running router on it anyway", cell, null, polysInConnection);
 
911
                                } else
 
912
                                {
 
913
                                        warn("Not routing network " + nr.getName() + " because it is already routed in the circuit", cell, null, polysInConnection);
 
914
                                        continue;
 
915
                                }
 
916
                        }
805
917
 
806
918
                        // route the segment
807
919
                        Runnable[] runnables = findPath(nr);
810
922
                                        runnable.run();
811
923
                                }
812
924
                        }
813
 
                }
814
 
        }
 
925
                        if (nr.debuggingRouteFromA != null)
 
926
                        {
 
927
                                // this NeededRoute was being debugged, so stop now
 
928
                                RoutingDebug.debugRoute(nr);
 
929
                                break;
 
930
                        }
 
931
                }
 
932
        }
 
933
 
 
934
        private void addNetsToList(RTNode<SOGBound> node, MutableInteger net, List<PolyBase> polysInConnection)
 
935
        {
 
936
                for(int i=0; i<node.getTotal(); i++)
 
937
                {
 
938
                        if (node.getFlag())
 
939
                        {
 
940
                                SOGBound b = (SOGBound)node.getChild(i);
 
941
                                if (b.getNetID() == null) continue;
 
942
                                if (b.getNetID().intValue() == net.intValue())
 
943
                                {
 
944
                                        ERectangle rect = b.bound;
 
945
                                        polysInConnection.add(new PolyBase(rect));
 
946
                                }
 
947
                        } else
 
948
                        {
 
949
                                RTNode<SOGBound> subNode = (RTNode)node.getChild(i);
 
950
                                addNetsToList(subNode, net, polysInConnection);
 
951
                        }
 
952
                }
 
953
        }
 
954
 
 
955
        /**
 
956
         * Method to retrieve ErrorLogger associated with SoG
 
957
         * @return pointer to ErrorLogger
 
958
         */
 
959
        public ErrorLogger getErrorLgger() { return this.errorLogger;}
815
960
 
816
961
        /**
817
962
         * Public interface that encapsulates interaction of SeaOfGatesEngines with outer environment
916
1061
        /**
917
1062
         * Class to hold a "batch" of NeededRoute objects, all on the same network.
918
1063
         */
919
 
        private class RouteBatch implements Comparable<RouteBatch>
 
1064
        class RouteBatch implements Comparable<RouteBatch>
920
1065
        {
921
1066
                Set<ArcInst> unroutedArcs;
922
1067
                Set<NodeInst> unroutedNodes;
923
1068
                List<NeededRoute> routesInBatch;
924
1069
                boolean isPwrGnd;
925
1070
                double length;
 
1071
                String netName;
926
1072
                private RouteResolution resolution;
927
1073
                private final ReentrantLock completedRouteLock = new ReentrantLock();
928
1074
 
929
 
                public RouteBatch()
 
1075
                public RouteBatch(String nn)
930
1076
                {
931
1077
                        unroutedArcs = new HashSet<ArcInst>();
932
1078
                        unroutedNodes = new HashSet<NodeInst>();
935
1081
                        resolution = new RouteResolution(destCellId);
936
1082
                        isPwrGnd = false;
937
1083
                        length = 0;
 
1084
                        netName = nn;
938
1085
                }
939
1086
 
940
1087
                public void addRoute(NeededRoute nr)
942
1089
                        routesInBatch.add(nr);
943
1090
                }
944
1091
 
945
 
                private void completedRoute(NeededRoute nr, Wavefront winningWF)
 
1092
                private void completedRoute(NeededRoute nr, Wavefront winningWF, SearchVertex result)
946
1093
                {
947
1094
                        completedRouteLock.lock();
 
1095
                        nr.winningWF = winningWF;
948
1096
                        try {
949
1097
                                if (winningWF != null && winningWF.vertices != null) {
950
1098
                                        // if route was successful, setup geometry for it
951
1099
                                        winningWF.createRoute();
952
1100
                                }
953
1101
 
954
 
                                if (unroutedArcs.size() > 0 || unroutedNodes.size() > 0)
955
 
                                {
956
 
                                        // remove the original unrouted nodes/arcs
957
 
                                        for (ArcInst aiKill : unroutedArcs) resolution.killArc(aiKill);
958
 
                                        for (NodeInst niKill : unroutedNodes) resolution.killNode(niKill);
959
 
                                        unroutedArcs.clear();
960
 
                                        unroutedNodes.clear();
961
 
                                }
962
 
                                if (!DEBUGGRIDDING)
963
 
                                {
964
 
                                        handler.instantiate(resolution);
965
 
 
966
 
                                        // schedule routing of any taps on a spine
967
 
                                        if (nr.spineTaps != null)
 
1102
                                // remove the original unrouted nodes/arcs
 
1103
                                for (ArcInst aiKill : unroutedArcs) resolution.killArc(aiKill);
 
1104
                                for (NodeInst niKill : unroutedNodes) resolution.killNode(niKill);
 
1105
                                unroutedArcs.clear();
 
1106
                                unroutedNodes.clear();
 
1107
 
 
1108
                                handler.instantiate(resolution);
 
1109
 
 
1110
                                // schedule routing of any taps on a spine
 
1111
                                if (nr.spineTaps != null)
 
1112
                                {
 
1113
                                        handler.flush(true);
 
1114
                                        int tapNumber = 1;
 
1115
                                        for(SearchVertex sv : nr.spineTapMap.keySet())
968
1116
                                        {
969
 
                                                handler.flush(true);
970
 
                                                int tapNumber = 1;
971
 
                                                for(SearchVertex sv : nr.spineTapMap.keySet())
 
1117
                                                PortInst aPi = nr.spineTapMap.get(sv);
 
1118
                                                ArcProto aArc = getMetalArcOnPort(aPi);
 
1119
                                                ImmutableNodeInst ini = nr.spineTapNIMap.get(aPi);
 
1120
                                                if (ini != null)
972
1121
                                                {
973
 
                                                        PortInst aPi = nr.spineTapMap.get(sv);
974
 
                                                        ArcProto aArc = getMetalArcOnPort(aPi);
975
 
                                                        ImmutableNodeInst ini = nr.spineTapNIMap.get(aPi);
976
 
                                                        if (ini != null)
 
1122
                                                        NodeInst ni = cell.getNodeById(ini.nodeId);
 
1123
                                                        if (ni != null)
977
1124
                                                        {
978
 
                                                                NodeInst ni = cell.getNodeById(ini.nodeId);
979
 
                                                                if (ni != null)
 
1125
                                                                // schedule the route to make the tap
 
1126
                                                                PortInst bPi = ni.getOnlyPortInst();
 
1127
                                                                ArcProto bArc = getMetalArcOnPort(bPi);
 
1128
                                                                if (aArc != null && bArc != null)
980
1129
                                                                {
981
 
                                                                        // schedule the route to make the tap
982
 
                                                                        PortInst bPi = ni.getOnlyPortInst();
983
 
                                                                        ArcProto bArc = getMetalArcOnPort(bPi);
984
 
                                                                        if (aArc != null && bArc != null)
985
 
                                                                        {
986
 
                                                                                String routeName = nr.routeName;
987
 
                                                                                if (routeName.endsWith("(spine)"))
988
 
                                                                                        routeName = routeName.substring(0, routeName.length()-1) + " tap " + tapNumber + ")";
989
 
                                                                                NeededRoute nrTap = new NeededRoute(routeName, aPi, bPi, aArc, bArc, null, nr.minWidth);
990
 
                                                                                if (inValidPort(aPi, nrTap) || inValidPort(bPi, nrTap)) continue;
991
 
                                                                                nrTap.setNetID(nr.netID);
992
 
                                                                                nrTap.growNetwork();
993
 
                                                                                tapRoutes.add(nrTap);
994
 
                                                                                nrTap.setBatchInfo(nr.batch, tapNumber++);
995
 
                                                                        }
 
1130
                                                                        String routeName = nr.routeName;
 
1131
                                                                        if (routeName.endsWith("(spine)"))
 
1132
                                                                                routeName = routeName.substring(0, routeName.length()-1) + " tap " + tapNumber + ")";
 
1133
                                                                        NeededRoute nrTap = new NeededRoute(routeName, aPi, bPi, aArc, bArc, null, nr.minWidth);
 
1134
                                                                        if (nrTap.invalidPort(true, aPi) || nrTap.invalidPort(false, bPi)) continue;
 
1135
                                                                        nrTap.setNetID(nr.netID);
 
1136
                                                                        nrTap.growNetwork();
 
1137
                                                                        tapRoutes.add(nrTap);
 
1138
                                                                        nrTap.setBatchInfo(nr.batch, tapNumber++);
996
1139
                                                                }
997
1140
                                                        }
998
1141
                                                }
1037
1180
                private final Rectangle2D routeBounds;
1038
1181
                private MutableInteger netID;
1039
1182
                private final double minWidth;
1040
 
                private final Rectangle2D jumpBound;
 
1183
                private Rectangle2D jumpBound;
1041
1184
                private int complexityLimit;
 
1185
                private int maxDistance;
1042
1186
                private double aX, aY, bX, bY;
 
1187
                private double aTaperWid, bTaperWid;
 
1188
                private double aTaperLen, bTaperLen;
1043
1189
                private FixpRectangle aRect, bRect;
1044
1190
                private FixpRectangle aRectGridded, bRectGridded;
1045
 
                private final int aZ, bZ;
1046
1191
                private final PortInst aPi, bPi;
 
1192
                private int aZ, bZ;
 
1193
                private int aC, bC;
 
1194
                private boolean alreadyRouted;
 
1195
                private Boolean debuggingRouteFromA;
 
1196
                private MetalVia replaceA, replaceB;
 
1197
                private int replaceAZ, replaceBZ;
 
1198
                private int replaceAC, replaceBC;
1047
1199
                private final List<PortInst> spineTaps;
1048
1200
                private final Map<SearchVertex,PortInst> spineTapMap;
1049
1201
                private final Map<PortInst,ImmutableNodeInst> spineTapNIMap;
1053
1205
                /** true when routed successfully */ private volatile boolean routedSuccess;
1054
1206
                private String errorMessage;
1055
1207
                /** true when this is the second try on the route */    private boolean reroute;
1056
 
                private double[][] gridLocationsX, gridLocationsY;
 
1208
                private SeaOfGatesTrack[][] gridLocationsX, gridLocationsY;
1057
1209
                private Map<SOGBound,Integer> extractList;
1058
 
                private boolean[] overridePreventArcs;
 
1210
                private boolean[] overridePreventArcs, forceGridArcs;
1059
1211
                private double[] overrideMetalWidth, overrideMetalSpacingX, overrideMetalSpacingY;
 
1212
                private double[][] overrideMetalSpacings;
 
1213
                private Wavefront winningWF, dirAtoB, dirBtoA;
 
1214
                private MessageLog loggedMessage;
1060
1215
 
1061
 
                public NeededRoute(String routeName, PortInst aPi, PortInst bPi, ArcProto aArc, ArcProto bArc, List<PortInst> spineTaps, double minWidth)
 
1216
                public NeededRoute(String routeName, PortInst aPi, PortInst bPi, ArcProto aArc, ArcProto bArc, 
 
1217
                        List<PortInst> spineTaps, double minWidth)
1062
1218
                {
1063
1219
                        // determine the coordinates of the route
 
1220
                        winningWF = null;
1064
1221
                        this.routeName = routeName;
1065
1222
                        this.minWidth = minWidth;
1066
1223
                        this.spineTaps = spineTaps;
1067
1224
                        this.complexityLimit = prefs.complexityLimit;
 
1225
                        this.maxDistance = prefs.maxDistance;
 
1226
                        alreadyRouted = false;
 
1227
                        replaceA = replaceB = null;
 
1228
                        replaceAZ = replaceBZ = 0;
 
1229
                        replaceAC = replaceBC = 0;
1068
1230
                        if (spineTaps == null)
1069
1231
                        {
1070
1232
                                spineTapMap = null;
1076
1238
                        }
1077
1239
                        overrideMetalWidth = null;
1078
1240
                        overrideMetalSpacingX = overrideMetalSpacingY = null;
 
1241
                        overrideMetalSpacings = new double[numMetalLayers][];
 
1242
 
1079
1243
                        for(int z=0; z<numMetalLayers; z++)
1080
1244
                        {
1081
 
                                Double overrideWidth = sogp.getDefaultWidthOverride(metalArcs[z]);
1082
 
                                SeaOfGatesArcProperties sogap = sogp.getOverridesForArcsOnNet(routeName, metalArcs[z]);
1083
 
                                if (sogap != null && sogap.getWidthOverride() != null) overrideWidth = sogap.getWidthOverride();
1084
 
                                if (overrideWidth != null)
1085
 
                                {
1086
 
                                        if (overrideMetalWidth == null)
1087
 
                                        {
1088
 
                                                overrideMetalWidth = new double[numMetalLayers];
1089
 
                                                for (int i = 0; i < numMetalLayers; i++)
1090
 
                                                        overrideMetalWidth[i] = Math.max(metalArcs[i].getDefaultLambdaBaseWidth(ep), minWidth);
1091
 
                                        }
1092
 
                                        overrideMetalWidth[z] = overrideWidth.doubleValue();
1093
 
                                }
1094
 
                                Double overrideSpacing = sogp.getDefaultSpacingOverride(metalArcs[z]);
1095
 
                                if (sogap != null && sogap.getSpacingOverride() != null) overrideSpacing = sogap.getSpacingOverride();
1096
 
                                if (overrideSpacing != null)
1097
 
                                {
1098
 
                                        if (overrideMetalSpacingX == null)
1099
 
                                        {
1100
 
                                                overrideMetalSpacingX = new double[numMetalLayers];
1101
 
                                                overrideMetalSpacingY = new double[numMetalLayers];
1102
 
                                                for (int i = 0; i < numMetalLayers; i++)
1103
 
                                                {
1104
 
                                                        overrideMetalSpacingX[i] = overrideMetalSpacingY[i] = 0;
1105
 
                                                        DRCTemplate rule = DRC.getSpacingRule(metalLayers[i], null, metalLayers[i], null,
1106
 
                                                                false, -1, metalArcs[i].getDefaultLambdaBaseWidth(ep), 50);
1107
 
                                                        if (rule != null)
1108
 
                                                        {
1109
 
                                                                overrideMetalSpacingX[i] = rule.getValue(0);
1110
 
                                                                if (rule.getNumValues() <= 1) overrideMetalSpacingY[i] = overrideMetalSpacingX[i]; else
1111
 
                                                                        overrideMetalSpacingY[i] = rule.getValue(1);
1112
 
                                                                        
1113
 
                                                        }
1114
 
                                                }
1115
 
                                        }
1116
 
                                        overrideMetalSpacingX[z] = overrideMetalSpacingY[z] = overrideSpacing.doubleValue();
1117
 
                                }
 
1245
                                overrideMetalSpacings[z] = null;
 
1246
                                Double overrideWidth = null;
 
1247
                                boolean hadXOverride = false, hadYOverride = false;
 
1248
                                for(int c=0; c<metalArcs[z].length; c++)
 
1249
                                {
 
1250
                                        Double o = sogp.getDefaultWidthOverride(metalArcs[z][c]);
 
1251
                                        if (o == null) continue;
 
1252
                                        if (overrideWidth == null || o.doubleValue() > overrideWidth.doubleValue()) overrideWidth = o;
 
1253
 
 
1254
                                        SeaOfGatesArcProperties sogap = sogp.getOverridesForArcsOnNet(routeName, metalArcs[z][c]);
 
1255
                                        if (sogap != null && sogap.getWidthOverride() != null) overrideWidth = sogap.getWidthOverride();
 
1256
                                        if (overrideWidth != null)
 
1257
                                        {
 
1258
                                                if (overrideMetalWidth == null)
 
1259
                                                {
 
1260
                                                        overrideMetalWidth = new double[numMetalLayers];
 
1261
                                                        for (int i = 0; i < numMetalLayers; i++)
 
1262
                                                        {
 
1263
                                                                if (metalArcs[i] == null) continue;
 
1264
                                                                for(int cc=0; cc<metalArcs[i].length; cc++)
 
1265
                                                                        overrideMetalWidth[i] = Math.max(metalArcs[i][cc].getDefaultLambdaBaseWidth(ep), minWidth);
 
1266
                                                        }
 
1267
                                                }
 
1268
                                                overrideMetalWidth[z] = overrideWidth.doubleValue();
 
1269
                                        }
 
1270
 
 
1271
                                        Double overrideSpacingX = sogp.getDefaultSpacingOverride(metalArcs[z][c], 0);
 
1272
                                        Double overrideSpacingY = sogp.getDefaultSpacingOverride(metalArcs[z][c], 1);
 
1273
                                        if (sogap != null && sogap.getSpacingOverride(0) != null) overrideSpacingX = sogap.getSpacingOverride(0);
 
1274
                                        if (sogap != null && sogap.getSpacingOverride(1) != null) overrideSpacingY = sogap.getSpacingOverride(1);
 
1275
                                        
 
1276
                                        if (overrideSpacingX != null)
 
1277
                                        {
 
1278
                                                hadXOverride = true;
 
1279
                                                if (overrideMetalSpacingX == null) // first time? 
 
1280
                                                {
 
1281
                                                        overrideMetalSpacingX = new double[numMetalLayers];
 
1282
                                                        for (int i = 0; i < numMetalLayers; i++)
 
1283
                                                        {
 
1284
                                                                overrideMetalSpacingX[i] = 0;
 
1285
                                                                if (metalLayers[i] == null || metalArcs[i] == null) continue;
 
1286
                                                                for(int cc=0; cc<metalArcs[i].length; cc++)
 
1287
                                                                {
 
1288
                                                                        DRCTemplate rule = DRC.getSpacingRule(metalLayers[i][cc], null, metalLayers[i][cc], null,
 
1289
                                                                                false, -1, metalArcs[i][cc].getDefaultLambdaBaseWidth(ep), 50);
 
1290
                                                                        if (rule != null)
 
1291
                                                                                overrideMetalSpacingX[i] = rule.getValue(0);
 
1292
                                                                }
 
1293
                                                        }
 
1294
                                                }
 
1295
                                                overrideMetalSpacingX[z] = overrideSpacingX.doubleValue();
 
1296
                                        }
 
1297
                                        if (overrideSpacingY != null)
 
1298
                                        {
 
1299
                                                hadYOverride = true;
 
1300
                                                if (overrideMetalSpacingY == null) // first time? 
 
1301
                                                {
 
1302
                                                        overrideMetalSpacingY = new double[numMetalLayers];
 
1303
                                                        for (int i = 0; i < numMetalLayers; i++)
 
1304
                                                        {
 
1305
                                                                overrideMetalSpacingY[i] = 0;
 
1306
                                                                if (metalLayers[i] == null || metalArcs[i] == null) continue;
 
1307
                                                                for(int cc=0; cc<metalArcs[i].length; cc++)
 
1308
                                                                {
 
1309
                                                                        DRCTemplate rule = DRC.getSpacingRule(metalLayers[i][cc], null, metalLayers[i][cc], null,
 
1310
                                                                                false, -1, metalArcs[i][cc].getDefaultLambdaBaseWidth(ep), 50);
 
1311
                                                                        if (rule != null)
 
1312
                                                                        {
 
1313
                                                                                if (rule.getNumValues() <= 1) overrideMetalSpacingY[i] = rule.getValue(0); else
 
1314
                                                                                        overrideMetalSpacingY[i] = rule.getValue(1);
 
1315
                                                                        }
 
1316
                                                                }
 
1317
                                                        }
 
1318
                                                }
 
1319
                                                overrideMetalSpacingY[z] = overrideSpacingY.doubleValue();
 
1320
                                        }
 
1321
                                }
 
1322
                                if (hadXOverride && hadYOverride)
 
1323
                                        overrideMetalSpacings[z] = new double[] {overrideMetalSpacingX[z], overrideMetalSpacingY[z]};
1118
1324
                        }
1119
1325
 
1120
1326
                        this.aPi = aPi;
1155
1361
 
1156
1362
                        aZ = aArc.getFunction().getLevel() - 1;
1157
1363
                        bZ = bArc.getFunction().getLevel() - 1;
 
1364
                        aC = aArc.getMaskLayer();
 
1365
                        bC = bArc.getMaskLayer();
1158
1366
 
1159
1367
                        double lowX = Math.min(aRect.getMinX(), bRect.getMinX()), highX = Math.max(aRect.getMaxX(), bRect.getMaxX());
1160
1368
                        double lowY = Math.min(aRect.getMinY(), bRect.getMinY()), highY = Math.max(aRect.getMaxY(), bRect.getMaxY());
1161
1369
 
1162
1370
                        // first construct a grid for an immense bound
1163
 
                        double gap = DRC.getWorstSpacingDistance(tech, -1) * 100;
 
1371
                        // original value was 100
 
1372
                        double gap = DRC.getWorstSpacingDistance(tech, -1) * maxDistance;
1164
1373
                        Rectangle2D testBounds = new Rectangle2D.Double(lowX - gap, lowY - gap, highX - lowX + gap * 2, highY - lowY + gap * 2);
1165
1374
                        buildGrids(testBounds);
1166
1375
 
1167
1376
                        // now expand the end bounds to reach grid locations
1168
 
                        double aLX = getLowerXGrid(aZ, aRect.getMinX());
1169
 
                        double aHX = getUpperXGrid(aZ, aRect.getMaxX());
1170
 
                        double aLY = getLowerYGrid(aZ, aRect.getMinY());
1171
 
                        double aHY = getUpperYGrid(aZ, aRect.getMaxY());
 
1377
                        double aLX = getLowerXGrid(aZ, aRect.getMinX()).getCoordinate();
 
1378
                        double aHX = getUpperXGrid(aZ, aRect.getMaxX()).getCoordinate();
 
1379
                        double aLY = getLowerYGrid(aZ, aRect.getMinY()).getCoordinate();
 
1380
                        double aHY = getUpperYGrid(aZ, aRect.getMaxY()).getCoordinate();
1172
1381
                        aRectGridded = FixpRectangle.from(new Rectangle2D.Double(aLX, aLY, aHX-aLX, aHY-aLY));
1173
 
                        double bLX = getLowerXGrid(bZ, bRect.getMinX());
1174
 
                        double bHX = getUpperXGrid(bZ, bRect.getMaxX());
1175
 
                        double bLY = getLowerYGrid(bZ, bRect.getMinY());
1176
 
                        double bHY = getUpperYGrid(bZ, bRect.getMaxY());
 
1382
                        double bLX = getLowerXGrid(bZ, bRect.getMinX()).getCoordinate();
 
1383
                        double bHX = getUpperXGrid(bZ, bRect.getMaxX()).getCoordinate();
 
1384
                        double bLY = getLowerYGrid(bZ, bRect.getMinY()).getCoordinate();
 
1385
                        double bHY = getUpperYGrid(bZ, bRect.getMaxY()).getCoordinate();
1177
1386
                        bRectGridded = FixpRectangle.from(new Rectangle2D.Double(bLX, bLY, bHX-bLX, bHY-bLY));
1178
1387
 
1179
1388
                        // now define bounds as the gridded envelope of a smaller bound
1180
 
                        double maxStrayFromRouteBoundsX = DRC.getWorstSpacingDistance(tech, -1) * 2;
1181
 
                        double maxStrayFromRouteBoundsY = maxStrayFromRouteBoundsX;
1182
 
                        double griddedLowX = Math.min(getLowerXGrid(aZ, lowX-maxStrayFromRouteBoundsX), getLowerXGrid(bZ, lowX-maxStrayFromRouteBoundsX));
1183
 
                        double griddedHighX = Math.max(getUpperXGrid(aZ, highX+maxStrayFromRouteBoundsX), getUpperXGrid(bZ, highX+maxStrayFromRouteBoundsX));
1184
 
                        double griddedLowY = Math.min(getLowerYGrid(aZ, lowY-maxStrayFromRouteBoundsY), getLowerYGrid(bZ, lowY-maxStrayFromRouteBoundsY));
1185
 
                        double griddedHighY = Math.max(getUpperYGrid(aZ, highY+maxStrayFromRouteBoundsY), getUpperYGrid(bZ, highY+maxStrayFromRouteBoundsY));
 
1389
                        double maxStrayFromRouteBoundsX = gap, maxStrayFromRouteBoundsY = gap;
 
1390
                        double griddedLowX = Math.min(getLowerXGrid(aZ, lowX-maxStrayFromRouteBoundsX).getCoordinate(), getLowerXGrid(bZ, lowX-maxStrayFromRouteBoundsX).getCoordinate());
 
1391
                        double griddedHighX = Math.max(getUpperXGrid(aZ, highX+maxStrayFromRouteBoundsX).getCoordinate(), getUpperXGrid(bZ, highX+maxStrayFromRouteBoundsX).getCoordinate());
 
1392
                        double griddedLowY = Math.min(getLowerYGrid(aZ, lowY-maxStrayFromRouteBoundsY).getCoordinate(), getLowerYGrid(bZ, lowY-maxStrayFromRouteBoundsY).getCoordinate());
 
1393
                        double griddedHighY = Math.max(getUpperYGrid(aZ, highY+maxStrayFromRouteBoundsY).getCoordinate(), getUpperYGrid(bZ, highY+maxStrayFromRouteBoundsY).getCoordinate());
 
1394
                        if (routingBoundsLimit != null)
 
1395
                        {
 
1396
                                if (griddedLowX < routingBoundsLimit.getMinX()) griddedLowX = routingBoundsLimit.getMinX();
 
1397
                                if (griddedHighX > routingBoundsLimit.getMaxX()) griddedHighX = routingBoundsLimit.getMaxX();
 
1398
                                if (griddedLowY < routingBoundsLimit.getMinY()) griddedLowY = routingBoundsLimit.getMinY();
 
1399
                                if (griddedHighY > routingBoundsLimit.getMaxY()) griddedHighY = routingBoundsLimit.getMaxY();
 
1400
                        }
1186
1401
                        routeBounds = new Rectangle2D.Double(griddedLowX, griddedLowY, griddedHighX - griddedLowX, griddedHighY - griddedLowY);
1187
1402
                        jumpBound = new Rectangle2D.Double(Math.min(aX, bX), Math.min(aY, bY), Math.abs(aX-bX), Math.abs(aY-bY));
1188
1403
 
1199
1414
                                        overridePreventArcs[metNum] = false;
1200
1415
                                }
1201
1416
                        }
1202
 
                }
1203
 
 
1204
 
                public double[][] getXRoutingGrid() { return gridLocationsX; }
1205
 
 
1206
 
                public double[][] getYRoutingGrid() { return gridLocationsY; }
 
1417
                        forceGridArcs = new boolean[numMetalLayers];
 
1418
                        for(int i=0; i<numMetalLayers; i++)
 
1419
                        {
 
1420
                                forceGridArcs[i] = false;
 
1421
                                for(int c=0; c<metalArcs[i].length; c++)
 
1422
                                        if (sogp.isGridForced(metalArcs[i][c])) forceGridArcs[i] = true;
 
1423
                        }
 
1424
 
 
1425
                        // determine the taper widths
 
1426
                        aTaperWid = getTaperWidth(aPi, aZ);
 
1427
                        bTaperWid = getTaperWidth(bPi, bZ);
 
1428
                        aTaperLen = taperLength[aZ];
 
1429
                        bTaperLen = taperLength[bZ];
 
1430
                        if (aTaperWid == getUntaperedArcWidth(aZ)) aTaperLen = -1;
 
1431
                        if (bTaperWid == getUntaperedArcWidth(bZ)) bTaperLen = -1;
 
1432
                }
 
1433
 
 
1434
                public boolean getRoutedSucess() { return routedSuccess; }
 
1435
                public Wavefront getWavefront() { return winningWF; }
 
1436
                public Wavefront getWavefrontAtoB() { return dirAtoB; }
 
1437
                public Wavefront getWavefrontBtoA() { return dirBtoA; }
 
1438
                public String getErrorMessage() { return errorMessage; }
 
1439
 
 
1440
                public void setDebugging(Boolean fromA) { debuggingRouteFromA = fromA; }
 
1441
 
 
1442
                /**
 
1443
                 * Method to check the validity of the endpoints with respect to forced gridding.
 
1444
                 * If the grid is being forced and the endpoints are not on grid,
 
1445
                 * routing may fail (and a warning will be issued here).
 
1446
                 */
 
1447
                public void checkGridValidity()
 
1448
                {
 
1449
                        if (forceGridArcs[aZ])
 
1450
                        {
 
1451
                                boolean hor = true;
 
1452
                                if (sogp.isHorizontalEven())
 
1453
                                {
 
1454
                                        if ((aZ%2) == 0) hor = false;
 
1455
                                } else
 
1456
                                {
 
1457
                                        if ((aZ%2) != 0) hor = false;
 
1458
                                }
 
1459
                                if (!hor && !isOnXGrid(aZ, getAX()))
 
1460
                                {
 
1461
                                        List<EPoint> offGrid = new ArrayList<EPoint>(); offGrid.add(EPoint.fromLambda(aX, aY)); offGrid.add(EPoint.fromLambda(aX, aY));
 
1462
                                        warn("Route " + routeName + ", end (" + TextUtils.formatDistance(aX) + "," + TextUtils.formatDistance(aY) + "," +
 
1463
                                                describeMetal(aZ,aC) + ") is not on X grid (nearest X grids are at " + TextUtils.formatDistance(getLowerXGrid(aZ, aX).getCoordinate()) +
 
1464
                                                " and " + TextUtils.formatDistance(getUpperXGrid(aZ, aX).getCoordinate()) + "). Route may fail.", cell, offGrid, null);
 
1465
                                }
 
1466
                                if (hor && !isOnYGrid(aZ, aY))
 
1467
                                {
 
1468
                                        List<EPoint> offGrid = new ArrayList<EPoint>(); offGrid.add(EPoint.fromLambda(aX, aY)); offGrid.add(EPoint.fromLambda(aX, aY));
 
1469
                                        warn("Route " + routeName + ", end (" + TextUtils.formatDistance(aX) + "," + TextUtils.formatDistance(aY) + "," +
 
1470
                                                describeMetal(aZ,aC) + ") is not on Y grid (nearest Y grids are at " + TextUtils.formatDistance(getLowerYGrid(aZ, aY).getCoordinate()) +
 
1471
                                                " and " + TextUtils.formatDistance(getUpperYGrid(aZ, aY).getCoordinate()) + "). Route may fail.", cell, offGrid, null);
 
1472
                                }
 
1473
                        }
 
1474
                        if (forceGridArcs[bZ])
 
1475
                        {
 
1476
                                boolean hor = true;
 
1477
                                if (sogp.isHorizontalEven())
 
1478
                                {
 
1479
                                        if ((bZ%2) == 0) hor = false;
 
1480
                                } else
 
1481
                                {
 
1482
                                        if ((bZ%2) != 0) hor = false;
 
1483
                                }
 
1484
                                if (!hor && !isOnXGrid(bZ, bX))
 
1485
                                {
 
1486
                                        List<EPoint> offGrid = new ArrayList<EPoint>(); offGrid.add(EPoint.fromLambda(bX, bY)); offGrid.add(EPoint.fromLambda(bX, bY));
 
1487
                                        warn("Route " + routeName + ", end (" + TextUtils.formatDistance(bX) + "," + TextUtils.formatDistance(bY) + "," +
 
1488
                                                describeMetal(bZ,bC) + ") is not on X grid (nearest X grids are at " + TextUtils.formatDistance(getLowerXGrid(bZ, bX).getCoordinate()) +
 
1489
                                                " and " + TextUtils.formatDistance(getUpperXGrid(bZ, bX).getCoordinate()) + "). Route may fail.", cell, offGrid, null);
 
1490
                                }
 
1491
                                if (hor && !isOnYGrid(bZ, bY))
 
1492
                                {
 
1493
                                        List<EPoint> offGrid = new ArrayList<EPoint>(); offGrid.add(EPoint.fromLambda(bX, bY)); offGrid.add(EPoint.fromLambda(bX, bY));
 
1494
                                        warn("Route " + routeName + ", end (" + TextUtils.formatDistance(bX) + "," + TextUtils.formatDistance(bY) + "," +
 
1495
                                                describeMetal(bZ,bC) + ") is not on Y grid (nearest Y grids are at " + TextUtils.formatDistance(getLowerYGrid(bZ, bY).getCoordinate()) +
 
1496
                                                " and " + TextUtils.formatDistance(getUpperYGrid(bZ, bY).getCoordinate()) + "). Route may fail.", cell, offGrid, null);
 
1497
                                }
 
1498
                        }
 
1499
                }
 
1500
 
 
1501
                public FixpRectangle getAGriddedRect() { return aRectGridded; }
 
1502
 
 
1503
                public FixpRectangle getBGriddedRect() { return bRectGridded; }
 
1504
 
 
1505
                public SeaOfGatesTrack[][] getXRoutingGrid() { return gridLocationsX; }
 
1506
 
 
1507
                public SeaOfGatesTrack[][] getYRoutingGrid() { return gridLocationsY; }
1207
1508
 
1208
1509
                /**
1209
1510
                 * Method to construct grids for all layers in the vicinity of this route.
1210
1511
                 */
1211
1512
                public void buildGrids(Rectangle2D bounds)
1212
1513
                {
1213
 
                        gridLocationsX = new double[numMetalLayers][];
1214
 
                        gridLocationsY = new double[numMetalLayers][];
 
1514
                        gridLocationsX = new SeaOfGatesTrack[numMetalLayers][];
 
1515
                        gridLocationsY = new SeaOfGatesTrack[numMetalLayers][];
1215
1516
 
1216
1517
                        // first make the grid positions for each layer
1217
1518
                        for(int metNum=1; metNum<=numMetalLayers; metNum++)
1218
1519
                        {
1219
1520
                                int metIndex = metNum - 1;
1220
 
                                double[] thisGrid = metalGrid[metIndex];
 
1521
                                SeaOfGatesTrack[] thisGrid = metalGrid[metIndex];
1221
1522
                                if (thisGrid == null) continue;
1222
1523
                                if (!sogp.isForceHorVer() && !sogp.isFavorHorVer()) continue;
1223
1524
                                boolean hor = true;
1228
1529
                                {
1229
1530
                                        if ((metNum%2) == 0) hor = false;
1230
1531
                                }
1231
 
                                double offset = thisGrid[0];
1232
 
                                double range = thisGrid[thisGrid.length-1] - offset;
 
1532
                                double offset = thisGrid[0].getCoordinate();
 
1533
                                double range = thisGrid[thisGrid.length-1].getCoordinate() - offset;
 
1534
                                range += thisGrid[1].getCoordinate() - thisGrid[0].getCoordinate();
1233
1535
                                if (range > 0)
1234
1536
                                {
1235
 
                                        List<Double> values = new ArrayList<Double>();
 
1537
                                        List<SeaOfGatesTrack> values = new ArrayList<SeaOfGatesTrack>();
1236
1538
                                        double low, high;
1237
1539
                                        if (hor)
1238
1540
                                        {
1249
1551
                                        {
1250
1552
                                                for(int i=0; i<thisGrid.length; i++)
1251
1553
                                                {
1252
 
                                                        double val = v + thisGrid[i];
 
1554
                                                        double val = v + thisGrid[i].getCoordinate();
 
1555
                                                        int maskNum = thisGrid[i].getMaskNum();
1253
1556
                                                        if (val >= low && val <= high)
1254
 
                                                                values.add(new Double(val));
 
1557
                                                                values.add(new SeaOfGatesTrack(val, maskNum));
1255
1558
                                                }
1256
1559
                                        }
1257
1560
                                        if (values.size() >= 2)
1258
1561
                                        {
1259
1562
                                                if (hor)
1260
1563
                                                {
1261
 
                                                        gridLocationsY[metIndex] = new double[values.size()];
1262
 
                                                        for(int i=0; i<values.size(); i++) gridLocationsY[metIndex][i] = values.get(i).doubleValue();
 
1564
                                                        gridLocationsY[metIndex] = makeArrayOfUniqueTracks(values);
1263
1565
                                                } else
1264
1566
                                                {
1265
 
                                                        gridLocationsX[metIndex] = new double[values.size()];
1266
 
                                                        for(int i=0; i<values.size(); i++) gridLocationsX[metIndex][i] = values.get(i).doubleValue();
 
1567
                                                        gridLocationsX[metIndex] = makeArrayOfUniqueTracks(values);
1267
1568
                                                }
1268
1569
                                        }
1269
1570
                                }
1282
1583
                                        if ((metNum%2) == 0) hor = false;
1283
1584
                                }
1284
1585
 
1285
 
                                Set<Double> values = new TreeSet<Double>();
 
1586
                                SeaOfGatesTrack[][] gridLocations;
 
1587
                                SeaOfGatesTrack t1, t2;
1286
1588
                                if (hor)
1287
1589
                                {
1288
1590
                                        // horizontal layer: combine X locations from upper and lower layers
1289
 
                                        if (metIndex > 0 && gridLocationsX[metIndex-1] != null)
1290
 
                                        {
1291
 
                                                for(int i=0; i<gridLocationsX[metIndex-1].length; i++)
1292
 
                                                        values.add(new Double(gridLocationsX[metIndex-1][i]));
1293
 
                                        }
1294
 
                                        if (metIndex < numMetalLayers-1 && gridLocationsX[metIndex+1] != null)
1295
 
                                        {
1296
 
                                                for(int i=0; i<gridLocationsX[metIndex+1].length; i++)
1297
 
                                                        values.add(new Double(gridLocationsX[metIndex+1][i]));
1298
 
                                        }
1299
 
                                        if (values.size() >= 2)
1300
 
                                        {
1301
 
                                                gridLocationsX[metIndex] = new double[values.size()];
1302
 
                                                int i=0;   for(Double v : values) gridLocationsX[metIndex][i++] = v.doubleValue();
1303
 
                                        }
 
1591
                                        gridLocations = gridLocationsX;
 
1592
                                        t1 = getClosestXGrid(aZ, aX);
 
1593
                                        t2 = getClosestXGrid(bZ, bX);
1304
1594
                                } else
1305
1595
                                {
1306
1596
                                        // vertical layer: combine Y locations from upper and lower layers
1307
 
                                        if (metIndex > 0 && gridLocationsY[metIndex-1] != null)
1308
 
                                        {
1309
 
                                                for(int i=0; i<gridLocationsY[metIndex-1].length; i++)
1310
 
                                                        values.add(new Double(gridLocationsY[metIndex-1][i]));
1311
 
                                        }
1312
 
                                        if (metIndex < numMetalLayers-1 && gridLocationsY[metIndex+1] != null)
1313
 
                                        {
1314
 
                                                for(int i=0; i<gridLocationsY[metIndex+1].length; i++)
1315
 
                                                        values.add(new Double(gridLocationsY[metIndex+1][i]));
1316
 
                                        }
1317
 
                                        if (values.size() >= 2)
1318
 
                                        {
1319
 
                                                gridLocationsY[metIndex] = new double[values.size()];
1320
 
                                                int i=0;   for(Double v : values) gridLocationsY[metIndex][i++] = v.doubleValue();
1321
 
                                        }
1322
 
                                }
1323
 
                        }
 
1597
                                        gridLocations = gridLocationsY;
 
1598
                                        t1 = getClosestXGrid(aZ, aY);
 
1599
                                        t2 = getClosestXGrid(bZ, bY);
 
1600
                                }
 
1601
                                List<SeaOfGatesTrack> values = new ArrayList<SeaOfGatesTrack>();
 
1602
                                boolean realGrid = false;
 
1603
                                if (metIndex > 0)
 
1604
                                        realGrid |= gridAlternateLayer(metIndex, -1, values, t1, t2, gridLocations);
 
1605
                                if (metIndex < numMetalLayers-1)
 
1606
                                        realGrid |= gridAlternateLayer(metIndex, 1, values, t1, t2, gridLocations);
 
1607
                                if (realGrid)
 
1608
                                {
 
1609
                                        gridLocations[metIndex] = makeArrayOfUniqueTracks(values);
 
1610
                                }
 
1611
                        }
 
1612
                }
 
1613
 
 
1614
                private SeaOfGatesTrack[] makeArrayOfUniqueTracks(List<SeaOfGatesTrack> values)
 
1615
                {
 
1616
                        Collections.sort(values);
 
1617
                        for(int i=1; i<values.size(); i++)
 
1618
                        {
 
1619
                                if (DBMath.areEquals(values.get(i-1).getCoordinate(), values.get(i).getCoordinate()))
 
1620
                                {
 
1621
                                        values.remove(i);
 
1622
                                        i--;
 
1623
                                }
 
1624
                        }
 
1625
                        SeaOfGatesTrack[] gridLocations = new SeaOfGatesTrack[values.size()];
 
1626
                        int i=0;
 
1627
                        for(SeaOfGatesTrack v : values) gridLocations[i++] = v;
 
1628
                        return gridLocations;
 
1629
                }
 
1630
 
 
1631
                /**
 
1632
                 * Method to consider an alternate layer's gridding when building the current layer's gridding information.
 
1633
                 * @param curLayer the metal layer being considered (0-based).
 
1634
                 * @param diff +1 or -1 to indicate the adjoining layer.
 
1635
                 * @param values a Set of Doubles with grid stops in the X/Y axis.
 
1636
                 * @param e1 the A endpoint coordinate (X or Y) to use if needed.
 
1637
                 * @param e1 the B endpoint coordinate (X or Y) to use if needed.
 
1638
                 * @param gridLocations the grid values (entry may be null)
 
1639
                 * @return true if there are real grid values applied from a neighboring layer.
 
1640
                 */
 
1641
                private boolean gridAlternateLayer(int curLayer, int diff, List<SeaOfGatesTrack> values, SeaOfGatesTrack t1, SeaOfGatesTrack t2, SeaOfGatesTrack[][] gridLocations)
 
1642
                {
 
1643
                        // if the current layer is blocked, ignore grid building on it
 
1644
                        if (sogp.isPrevented(primaryMetalArc[curLayer])) return false;
 
1645
 
 
1646
                        // if the alternate layer is blocked, ignore its grid factor
 
1647
                        int altLayer = curLayer + diff;
 
1648
 
 
1649
                        // if the alternate layer has no grid, use the endpoints of the route
 
1650
                        if (gridLocations[altLayer] == null)
 
1651
                        {
 
1652
                                values.add(t1);
 
1653
                                values.add(t2);
 
1654
                                return false;
 
1655
                        }
 
1656
 
 
1657
                        // alternate layer is gridded, so grid this layer with those stops
 
1658
                        for(int i=0; i<gridLocations[altLayer].length; i++)
 
1659
                                values.add(new SeaOfGatesTrack(gridLocations[altLayer][i].getCoordinate(), gridLocations[altLayer][i].getMaskNum()));
 
1660
                        return true;
1324
1661
                }
1325
1662
 
1326
1663
                /**
1329
1666
                 * @param value the X value to be adjusted.
1330
1667
                 * @return the closest X grid value at or below the given value.
1331
1668
                 */
1332
 
                public double getLowerXGrid(int metNum, double value)
 
1669
                public SeaOfGatesTrack getLowerXGrid(int metNum, double value)
1333
1670
                {
1334
1671
                        return findLowerValue(gridLocationsX[metNum], value);
1335
1672
                }
1340
1677
                 * @param value the X value to be adjusted.
1341
1678
                 * @return the closest X grid value at or above the given value.
1342
1679
                 */
1343
 
                public double getUpperXGrid(int metNum, double value)
 
1680
                public SeaOfGatesTrack getUpperXGrid(int metNum, double value)
1344
1681
                {
1345
1682
                        return findUpperValue(gridLocationsX[metNum], value);
1346
1683
                }
1351
1688
                 * @param value the X value to be adjusted.
1352
1689
                 * @return the closest X grid value to the given value.
1353
1690
                 */
1354
 
                public double getClosestXGrid(int metNum, double value)
 
1691
                public SeaOfGatesTrack getClosestXGrid(int metNum, double value)
1355
1692
                {
1356
1693
                        return findClosestValue(gridLocationsX[metNum], value);
1357
1694
                }
1362
1699
                 * @param value the Y value to be adjusted.
1363
1700
                 * @return the closest Y grid value at or below the given value.
1364
1701
                 */
1365
 
                public double getLowerYGrid(int metNum, double value)
 
1702
                public SeaOfGatesTrack getLowerYGrid(int metNum, double value)
1366
1703
                {
1367
1704
                        return findLowerValue(gridLocationsY[metNum], value);
1368
1705
                }
1373
1710
                 * @param value the Y value to be adjusted.
1374
1711
                 * @return the closest Y grid value at or above the given value.
1375
1712
                 */
1376
 
                public double getUpperYGrid(int metNum, double value)
 
1713
                public SeaOfGatesTrack getUpperYGrid(int metNum, double value)
1377
1714
                {
1378
1715
                        return findUpperValue(gridLocationsY[metNum], value);
1379
1716
                }
1384
1721
                 * @param value the Y value to be adjusted.
1385
1722
                 * @return the closest Y grid value to the given value.
1386
1723
                 */
1387
 
                public double getClosestYGrid(int metNum, double value)
 
1724
                public SeaOfGatesTrack getClosestYGrid(int metNum, double value)
1388
1725
                {
1389
1726
                        return findClosestValue(gridLocationsY[metNum], value);
1390
1727
                }
1399
1736
                        return isOnGrid(gridLocationsY[metNum], value);
1400
1737
                }
1401
1738
 
1402
 
                private double findLowerValue(double[] thisGrid, double value)
1403
 
                {
1404
 
                        if (thisGrid == null) return value;
1405
 
                        int lo = 0, hi = thisGrid.length - 1;
1406
 
                        if (value <= thisGrid[lo]) return value;
1407
 
                        if (value >= thisGrid[hi]) return value;
1408
 
 
1409
 
                        for(int i=0; i<1000; i++)
1410
 
                        {
1411
 
                                int med = (hi + lo) / 2;
1412
 
                                if (value >= thisGrid[med] && value < thisGrid[med+1]) return thisGrid[med];
1413
 
                                if (value < thisGrid[med]) hi = med; else lo = med;
1414
 
                        }
1415
 
                        return value;
1416
 
                }
1417
 
 
1418
 
                private double findUpperValue(double[] thisGrid, double value)
1419
 
                {
1420
 
                        if (thisGrid == null) return value;
1421
 
 
1422
 
                        int lo = 0, hi = thisGrid.length - 1;
1423
 
                        if (value <= thisGrid[lo]) return value;
1424
 
                        if (value >= thisGrid[hi]) return value;
1425
 
 
1426
 
                        for(int i=0; i<1000; i++)
1427
 
                        {
1428
 
                                int med = (hi + lo) / 2;
1429
 
                                if (value > thisGrid[med] && value <= thisGrid[med+1]) return thisGrid[med+1];
1430
 
                                if (value <= thisGrid[med]) hi = med; else lo = med;
1431
 
                        }
1432
 
                        return value;
1433
 
                }
1434
 
 
1435
 
                private double findClosestValue(double[] thisGrid, double value)
1436
 
                {
1437
 
                        if (thisGrid == null) return value;
1438
 
 
1439
 
                        int lo = 0, hi = thisGrid.length - 1;
1440
 
                        if (value <= thisGrid[lo]) return value;
1441
 
                        if (value >= thisGrid[hi]) return value;
1442
 
 
1443
 
                        for(int i=0; i<1000; i++)
1444
 
                        {
1445
 
                                int med = (hi + lo) / 2;
1446
 
                                if (value >= thisGrid[med] && value <= thisGrid[med+1])
 
1739
                private SeaOfGatesTrack findLowerValue(SeaOfGatesTrack[] thisGrid, double value)
 
1740
                {
 
1741
                        if (thisGrid == null) return new SeaOfGatesTrack(value, 0);
 
1742
                        int lo = 0, hi = thisGrid.length - 1;
 
1743
                        if (DBMath.isLessThanOrEqualTo(value, thisGrid[lo].getCoordinate())) return thisGrid[lo];
 
1744
                        if (DBMath.isGreaterThanOrEqualTo(value, thisGrid[hi].getCoordinate())) return thisGrid[hi];
 
1745
 
 
1746
                        for(int i=0; i<1000; i++)
 
1747
                        {
 
1748
                                int med = (hi + lo) / 2;
 
1749
                                if (DBMath.isGreaterThanOrEqualTo(value, thisGrid[med].getCoordinate()) &&
 
1750
                                        DBMath.isLessThan(value, thisGrid[med+1].getCoordinate())) return thisGrid[med];
 
1751
                                if (DBMath.isLessThan(value, thisGrid[med].getCoordinate())) hi = med; else lo = med;
 
1752
                        }
 
1753
                        return new SeaOfGatesTrack(value, 0);
 
1754
                }
 
1755
 
 
1756
                private SeaOfGatesTrack findUpperValue(SeaOfGatesTrack[] thisGrid, double value)
 
1757
                {
 
1758
                        if (thisGrid == null) return new SeaOfGatesTrack(value, 0);
 
1759
 
 
1760
                        int lo = 0, hi = thisGrid.length - 1;
 
1761
                        if (DBMath.isLessThanOrEqualTo(value, thisGrid[lo].getCoordinate())) return thisGrid[lo];
 
1762
                        if (DBMath.isGreaterThanOrEqualTo(value, thisGrid[hi].getCoordinate())) return thisGrid[hi];
 
1763
 
 
1764
                        for(int i=0; i<1000; i++)
 
1765
                        {
 
1766
                                int med = (hi + lo) / 2;
 
1767
                                if (DBMath.isGreaterThan(value, thisGrid[med].getCoordinate()) &&
 
1768
                                        DBMath.isLessThanOrEqualTo(value, thisGrid[med+1].getCoordinate())) return thisGrid[med+1];
 
1769
                                if (DBMath.isLessThanOrEqualTo(value, thisGrid[med].getCoordinate())) hi = med; else lo = med;
 
1770
                        }
 
1771
                        return new SeaOfGatesTrack(value, 0);
 
1772
                }
 
1773
 
 
1774
                private SeaOfGatesTrack findClosestValue(SeaOfGatesTrack[] thisGrid, double value)
 
1775
                {
 
1776
                        if (thisGrid == null) return new SeaOfGatesTrack(value, 0);
 
1777
 
 
1778
                        int lo = 0, hi = thisGrid.length - 1;
 
1779
                        if (DBMath.isLessThanOrEqualTo(value, thisGrid[lo].getCoordinate())) return thisGrid[lo];
 
1780
                        if (DBMath.isGreaterThanOrEqualTo(value, thisGrid[hi].getCoordinate())) return thisGrid[hi];
 
1781
 
 
1782
                        for(int i=0; i<1000; i++)
 
1783
                        {
 
1784
                                int med = (hi + lo) / 2;
 
1785
                                if (DBMath.isGreaterThanOrEqualTo(value, thisGrid[med].getCoordinate()) &&
 
1786
                                        DBMath.isLessThan(value, thisGrid[med+1].getCoordinate()))
1447
1787
                                {
1448
 
                                        if (value - thisGrid[med] < thisGrid[med+1] - value)
 
1788
                                        if (DBMath.isLessThan(value - thisGrid[med].getCoordinate(), thisGrid[med+1].getCoordinate() - value))
1449
1789
                                                return thisGrid[med];
1450
1790
                                        return thisGrid[med+1];
1451
1791
                                }
1452
 
                                if (value <= thisGrid[med]) hi = med; else lo = med;
 
1792
                                if (DBMath.isLessThanOrEqualTo(value, thisGrid[med].getCoordinate())) hi = med; else lo = med;
1453
1793
                        }
1454
 
                        return value;
 
1794
                        return new SeaOfGatesTrack(value, 0);
1455
1795
                }
1456
1796
 
1457
 
                private boolean isOnGrid(double[] thisGrid, double value)
 
1797
                private boolean isOnGrid(SeaOfGatesTrack[] thisGrid, double value)
1458
1798
                {
1459
1799
                        if (thisGrid != null)
1460
1800
                        {
1461
1801
                                int lo = 0, hi = thisGrid.length - 1;
1462
 
                                if (value < thisGrid[lo]) return false;
1463
 
                                if (value > thisGrid[hi]) return false;
 
1802
                                if (DBMath.isLessThan(value, thisGrid[lo].getCoordinate())) return false;
 
1803
                                if (DBMath.isGreaterThan(value, thisGrid[hi].getCoordinate())) return false;
1464
1804
 
1465
1805
                                for(int i=0; i<1000; i++)
1466
1806
                                {
1467
1807
                                        int med = (hi + lo) / 2;
1468
 
                                        if (value >= thisGrid[med] && value <= thisGrid[med+1])
 
1808
                                        if (DBMath.isGreaterThanOrEqualTo(value, thisGrid[med].getCoordinate()) &&
 
1809
                                                DBMath.isLessThanOrEqualTo(value, thisGrid[med+1].getCoordinate()))
1469
1810
                                        {
1470
 
                                                if (value == thisGrid[med] || thisGrid[med+1] == value)
 
1811
                                                if (DBMath.areEquals(value, thisGrid[med].getCoordinate()) ||
 
1812
                                                        DBMath.areEquals(thisGrid[med+1].getCoordinate(), value))
1471
1813
                                                        return true;
1472
1814
                                                return false;
1473
1815
                                        }
1474
 
                                        if (value <= thisGrid[med]) hi = med; else lo = med;
 
1816
                                        if (DBMath.isLessThanOrEqualTo(value, thisGrid[med].getCoordinate())) hi = med; else lo = med;
1475
1817
                                }
1476
1818
                                return false;
1477
1819
                        }
1518
1860
                        return Math.floor(v);
1519
1861
                }
1520
1862
 
1521
 
                public Wavefront[] makeWavefronts()
 
1863
                /**
 
1864
                 * Method to determine whether a contact can be placed that will connect existing metal to new metal.
 
1865
                 * @param np the contact.
 
1866
                 * @param newMetal the new metal layer (0-based).
 
1867
                 * @param offendingMetal the existing metal layer (0-based).
 
1868
                 * @param offendingMetalColor the mask color of the existing metal layer.
 
1869
                 * @param conX the X coordinate of the contact.
 
1870
                 * @param conY the Y coordinate of the contact.
 
1871
                 * @param conWid the width of the contact.
 
1872
                 * @param conHei the height of the contact.
 
1873
                 * @param orient the orientation of the contact.
 
1874
                 * @return true if the contact fits (the offending metal already exists and the new metal is available).
 
1875
                 */
 
1876
                private boolean canPlaceContact(PrimitiveNode np, int newMetal, int offendingMetal, int offendingMetalColor,
 
1877
                        double conX, double conY, double conWid, double conHei, Orientation orient, boolean endA)
 
1878
                {
 
1879
                        NodeInst dummyNi = NodeInst.makeDummyInstance(np, ep, EPoint.fromLambda(conX, conY), conWid, conHei, orient);
 
1880
                        Poly[] conPolys = tech.getShapeOfNode(dummyNi);
 
1881
                        FixpTransform trans = null;
 
1882
                        MutableInteger mi = new MutableInteger(netID.intValue() + (endA ? BLOCKAGEENDA : BLOCKAGEENDB));
 
1883
                        if (orient != Orientation.IDENT) trans = dummyNi.rotateOut();
 
1884
                        for (int p = 0; p < conPolys.length; p++)
 
1885
                        {
 
1886
                                Poly conPoly = conPolys[p];
 
1887
                                Layer conLayer = conPoly.getLayer();
 
1888
                                if (!conLayer.getFunction().isMetal()) continue;
 
1889
                                if (trans != null) conPoly.transform(trans);
 
1890
                                Rectangle2D conRect = conPoly.getBounds2D();
 
1891
 
 
1892
                                // if this is the offending metal layer, check to see that the geometry already exists
 
1893
                                boolean found = false;
 
1894
                                for(int c=0; c<metalLayers[offendingMetal].length; c++)
 
1895
                                        if (conLayer == metalLayers[offendingMetal][c] &&
 
1896
                                                conLayer.getFunction().getMaskColor() == offendingMetalColor) found = true;
 
1897
                                if  (found)
 
1898
                                {
 
1899
                                        if (!isPointInMetal(conRect.getMinX(), conRect.getMinY(), offendingMetal, mi) ||
 
1900
                                                !isPointInMetal(conRect.getMinX(), conRect.getMaxY(), offendingMetal, mi) ||
 
1901
                                                !isPointInMetal(conRect.getMaxX(), conRect.getMaxY(), offendingMetal, mi) ||
 
1902
                                                !isPointInMetal(conRect.getMaxX(), conRect.getMinY(), offendingMetal, mi) ||
 
1903
                                                !isPointInMetal(conRect.getCenterX(), conRect.getCenterY(), offendingMetal, mi))
 
1904
                                        {
 
1905
                                                // offending layer is not there: cannot place contact
 
1906
                                                return false;
 
1907
                                        }
 
1908
                                }
 
1909
 
 
1910
                                // if this is the new metal layer, make sure there is room for it
 
1911
                                found = false;
 
1912
                                for(int c=0; c<metalLayers[newMetal].length; c++)
 
1913
                                        if (conLayer == metalLayers[newMetal][c]) found = true;
 
1914
                                if  (found)
 
1915
                                {
 
1916
                                        double[] fromSurround = getSpacingRule(newMetal, maxDefArcWidth[newMetal], -1);
 
1917
                                        double halfWidth = conRect.getWidth() / 2;
 
1918
                                        double halfHeight = conRect.getHeight() / 2;
 
1919
                                        SOGBound block = getMetalBlockage(netID, newMetal, halfWidth, halfHeight, fromSurround, conRect.getCenterX(), conRect.getCenterY());
 
1920
                                        if (block != null) return false;
 
1921
                                }
 
1922
                        }
 
1923
                        return true;
 
1924
                }
 
1925
 
 
1926
                /**
 
1927
                 * Method to determine whether a point is covered by a metal layer on a given network.
 
1928
                 * @param x the X coordinate to search.
 
1929
                 * @param y the Y coordinate to search.
 
1930
                 * @param metalNo the metal number to consider.
 
1931
                 * @param netID the netID that must be on the metal (null to ignore this).
 
1932
                 * @return
 
1933
                 */
 
1934
                private boolean isPointInMetal(double x, double y, int metalNo, MutableInteger netID)
 
1935
                {
 
1936
                        // get the R-Tree data for the metal layer
 
1937
                        BlockageTree bTree = rTrees.getMetalTree(primaryMetalLayer[metalNo]);
 
1938
                        bTree.lock();
 
1939
                        try {
 
1940
                                if (bTree.isEmpty()) return false;
 
1941
 
 
1942
                                Rectangle2D searchArea = new Rectangle2D.Double(x, y, 0, 0);
 
1943
                                for (Iterator<SOGBound> sea = bTree.search(searchArea); sea.hasNext();)
 
1944
                                {
 
1945
                                        SOGBound sBound = sea.next();
 
1946
                                        if (sBound.containsPoint(x, y))
 
1947
                                        {
 
1948
                                                if (netID != null)
 
1949
                                                {
 
1950
                                                        if (!sBound.isSameBasicNet(netID)) continue;
 
1951
                                                        int endBits = BLOCKAGEENDA | BLOCKAGEENDB;
 
1952
                                                        if ((sBound.getNetID().intValue()&endBits) != (netID.intValue()&endBits)) continue;
 
1953
                                                }
 
1954
                                                return true;
 
1955
                                        }
 
1956
                                }
 
1957
                        } finally {
 
1958
                                bTree.unlock();
 
1959
                        }
 
1960
                        return false;
 
1961
                }
 
1962
 
 
1963
                /**
 
1964
                 * Method to determine the size and orientation of a contact.
 
1965
                 * @param mv the MetalVia describing the contact.
 
1966
                 * @param wid where the width will be stored.
 
1967
                 * @param hei where the height will be stored.
 
1968
                 * @return the orientation to use.
 
1969
                 */
 
1970
                private Orientation getMVSize(MetalVia mv, double x, double y, double lastX, double lastY, MutableDouble wid, MutableDouble hei)
 
1971
                {
 
1972
                        PrimitiveNode np = mv.via;
 
1973
                        Orientation orient = Orientation.fromJava(mv.orientation * 10, false, false);
 
1974
                        SizeOffset so = np.getProtoSizeOffset();
 
1975
                        double minWid = minWidth;
 
1976
                        double minHei = minWidth;
 
1977
                        double xOffset = so.getLowXOffset() + so.getHighXOffset();
 
1978
                        double yOffset = so.getLowYOffset() + so.getHighYOffset();
 
1979
                        double conWid = Math.max(np.getDefWidth(ep) - xOffset, minWid) + xOffset;
 
1980
                        double conHei = Math.max(np.getDefHeight(ep) - yOffset, minHei) + yOffset;
 
1981
                        if (mv.horMetal >= 0)
 
1982
                        {
 
1983
                                double arcWid = getArcWidth(mv.horMetal, x, y, lastX, lastY) + mv.horMetalInset;
 
1984
                                if (arcWid > conHei) conHei = arcWid;
 
1985
                        }
 
1986
                        if (mv.verMetal >= 0)
 
1987
                        {
 
1988
                                double arcWid = getArcWidth(mv.verMetal, x, y, lastX, lastY) + mv.verMetalInset;
 
1989
                                if (arcWid > conWid) conWid = arcWid;
 
1990
                        }
 
1991
                        wid.setValue(conWid);
 
1992
                        hei.setValue(conHei);
 
1993
                        return orient;
 
1994
                }
 
1995
 
 
1996
                /**
 
1997
                 * Method to tell whether an endpoint of the route is invalid.
 
1998
                 * @param endA true if the A end is being examined, false for the B end.
 
1999
                 * @param pi the port of the end being examined.
 
2000
                 * @return true if the endpoint is invalid and cannot be routed.
 
2001
                 * Gives error message if true.
 
2002
                 */
 
2003
                private boolean invalidPort(boolean endA, PortInst pi)
 
2004
                {
 
2005
                        // first see if any metal layer on this end is available
 
2006
                        ArcProto[] conns = getPossibleConnections(pi.getPortProto());
 
2007
                        for (int j = 0; j < conns.length; j++)
 
2008
                        {
 
2009
                                ArcProto ap = conns[j];
 
2010
                                if (ap.getTechnology() != tech) continue;
 
2011
                                if (!ap.getFunction().isMetal()) continue;
 
2012
                                if (preventArc(conns[j].getFunction().getLevel() - 1)) continue;
 
2013
                                return false;
 
2014
                        }
 
2015
 
 
2016
                        // determine location of contact
 
2017
                        double x = endA ? aX : bX, y = endA ? aY : bY;
 
2018
                        Map<Integer,List<PrimitiveNode>> whatWasChecked = new HashMap<Integer,List<PrimitiveNode>>();
 
2019
                        Map<Integer,java.awt.Point> contactInvalidColors = new HashMap<Integer,java.awt.Point>();
 
2020
                        int realOffendingMetal = 0;
 
2021
 
 
2022
                        // no metal layers available: see if a contact can be placed to shift to a valid layer
 
2023
                        EPoint pt = pi.getCenter();
 
2024
                        double conX = pt.getX(), conY = pt.getY();
 
2025
                        double endCoord = 0;
 
2026
                        if (sogp.isContactAllowedDownToAvoidedLayer() || sogp.isContactAllowedUpToAvoidedLayer())
 
2027
                        {
 
2028
                                // first see if an adjoining layer is available
 
2029
                                for (int j = 0; j < conns.length; j++)
 
2030
                                {
 
2031
                                        ArcProto ap = conns[j];
 
2032
                                        if (ap.getTechnology() != tech) continue;
 
2033
                                        if (!ap.getFunction().isMetal()) continue;
 
2034
                                        int offendingMetal = conns[j].getFunction().getLevel() - 1;
 
2035
                                        int offendingMetalColor = conns[j].getMaskLayer();
 
2036
                                        int newMetal = 0;
 
2037
                                        int newMetalColor = 0;
 
2038
                                        int lowerMetal = offendingMetal - 1;
 
2039
                                        int upperMetal = offendingMetal + 1;
 
2040
                                        List<MetalVia> mvs = null;
 
2041
                                        if (sogp.isContactAllowedUpToAvoidedLayer() && lowerMetal >= 0 && !preventArc(lowerMetal))
 
2042
                                        {
 
2043
                                                // can drop down one metal layer to connect
 
2044
                                                mvs = metalVias[lowerMetal].getVias();
 
2045
                                                newMetal = lowerMetal;
 
2046
                                        }
 
2047
                                        if (sogp.isContactAllowedDownToAvoidedLayer() && upperMetal < numMetalLayers && !preventArc(upperMetal))
 
2048
                                        {
 
2049
                                                // can move up one metal layer to connect
 
2050
                                                mvs = metalVias[upperMetal-1].getVias();
 
2051
                                                newMetal = upperMetal;
 
2052
                                        }
 
2053
                                        if (mvs == null) continue;
 
2054
 
 
2055
                                        // see if any contacts can be placed
 
2056
                                        List<PrimitiveNode> checkedThese = whatWasChecked.get(Integer.valueOf(newMetal));
 
2057
                                        if (checkedThese == null) whatWasChecked.put(Integer.valueOf(newMetal), checkedThese = new ArrayList<PrimitiveNode>());
 
2058
                                        boolean hasContacts = false;
 
2059
                                        for (MetalVia mv : mvs)
 
2060
                                        {
 
2061
                                                if (mv.horMetal == offendingMetal && mv.verMetal == newMetal)
 
2062
                                                {
 
2063
                                                        if (mv.horMetalColor != offendingMetalColor || mv.verMetalColor != newMetalColor) continue;
 
2064
                                                } else if (mv.verMetal == offendingMetal && mv.horMetal == newMetal)
 
2065
                                                {
 
2066
                                                        if (mv.verMetalColor != offendingMetalColor || mv.horMetalColor != newMetalColor) continue;
 
2067
                                                }
 
2068
                                                hasContacts = true;
 
2069
                                                checkedThese.add(mv.via);
 
2070
                                        }
 
2071
                                        if (!hasContacts)
 
2072
                                        {
 
2073
                                                realOffendingMetal = offendingMetal;
 
2074
                                                contactInvalidColors.put(Integer.valueOf(newMetal), new java.awt.Point(offendingMetalColor, newMetalColor));
 
2075
                                        }
 
2076
                                        MetalVia viaToPlace = null;
 
2077
                                        double viaToPlaceX = 0, viaToPlaceY = 0;
 
2078
                                        double viaSizeX = 0, viaSizeY = 0;
 
2079
                                        Orientation viaOrient = Orientation.IDENT;
 
2080
                                        boolean hor = true;
 
2081
                                        if (sogp.isHorizontalEven())
 
2082
                                        {
 
2083
                                                if ((newMetal%2) == 0) hor = false;
 
2084
                                        } else
 
2085
                                        {
 
2086
                                                if ((newMetal%2) != 0) hor = false;
 
2087
                                        }
 
2088
 
 
2089
                                        // adjust location of contact to be on grid
 
2090
                                        if (forceGridArcs[newMetal])
 
2091
                                        {
 
2092
                                                int index = 0, dir = 0;
 
2093
                                                if (hor)
 
2094
                                                {
 
2095
                                                        if (gridLocationsY[newMetal] != null)
 
2096
                                                        {
 
2097
                                                                double otherY = endA ? bY : aY;
 
2098
                                                                if (otherY < conY)
 
2099
                                                                {
 
2100
                                                                        conY = getLowerYGrid(newMetal, conY).getCoordinate();
 
2101
                                                                        dir = -1;
 
2102
                                                                } else
 
2103
                                                                {
 
2104
                                                                        conY = getUpperYGrid(newMetal, conY).getCoordinate();
 
2105
                                                                        dir = 1;
 
2106
                                                                }
 
2107
                                                                for(index=0; index<gridLocationsY[newMetal].length; index++)
 
2108
                                                                        if (gridLocationsY[newMetal][index].getCoordinate() == conY) break;
 
2109
                                                        }
 
2110
                                                } else
 
2111
                                                {
 
2112
                                                        if (gridLocationsX[newMetal] != null)
 
2113
                                                        {
 
2114
                                                                double otherX = endA ? bX : aX;
 
2115
                                                                if (otherX < conX)
 
2116
                                                                {
 
2117
                                                                        conX = getLowerXGrid(newMetal, conX).getCoordinate();
 
2118
                                                                        dir = -1;
 
2119
                                                                } else
 
2120
                                                                {
 
2121
                                                                        conX = getUpperXGrid(newMetal, conX).getCoordinate();
 
2122
                                                                        dir = 1;
 
2123
                                                                }
 
2124
                                                                for(index=0; index<gridLocationsX[newMetal].length; index++)
 
2125
                                                                        if (gridLocationsX[newMetal][index].getCoordinate() == conX) break;
 
2126
                                                        }
 
2127
                                                }
 
2128
 
 
2129
                                                // try all values on the grid, heading toward goal
 
2130
                                                int startIndex = index;
 
2131
 
 
2132
                                                // code to travel as far as possible rather than stopping at first valid location
 
2133
                                                if (hor)
 
2134
                                                {
 
2135
                                                        endCoord = endA ? bY : aY;
 
2136
                                                } else
 
2137
                                                {
 
2138
                                                        endCoord = endA ? bX : aX;
 
2139
                                                }
 
2140
                                                
 
2141
                                                for(;;)
 
2142
                                                {
 
2143
                                                        // more code to travel as far as possible rather than stopping at first valid location
 
2144
                                                        boolean tooFar = false;
 
2145
                                                        if (hor)
 
2146
                                                        {
 
2147
                                                                if (dir < 0)
 
2148
                                                                {
 
2149
                                                                        if (conY < endCoord) tooFar = true;
 
2150
                                                                } else
 
2151
                                                                {
 
2152
                                                                        if (conY > endCoord) tooFar = true;
 
2153
                                                                }
 
2154
                                                        } else
 
2155
                                                        {
 
2156
                                                                if (dir < 0)
 
2157
                                                                {
 
2158
                                                                        if (conX < endCoord) tooFar = true;
 
2159
                                                                } else
 
2160
                                                                {
 
2161
                                                                        if (conX > endCoord) tooFar = true;
 
2162
                                                                }
 
2163
                                                        }
 
2164
                                                        if (tooFar && viaToPlace != null) break;
 
2165
 
 
2166
                                                        newMetalColor = (hor ? gridLocationsY[newMetal][index].getMaskNum() : gridLocationsX[newMetal][index].getMaskNum());
 
2167
                                                        for (MetalVia mv : mvs)
 
2168
                                                        {
 
2169
                                                                if (mv.horMetal == offendingMetal && mv.verMetal == newMetal)
 
2170
                                                                {
 
2171
                                                                        if (mv.horMetalColor != offendingMetalColor || mv.verMetalColor != newMetalColor) continue;
 
2172
                                                                } else if (mv.verMetal == offendingMetal && mv.horMetal == newMetal)
 
2173
                                                                {
 
2174
                                                                        if (mv.verMetalColor != offendingMetalColor || mv.horMetalColor != newMetalColor) continue;
 
2175
                                                                }
 
2176
                                                                PrimitiveNode np = mv.via;
 
2177
                                                                MutableDouble conWid, conHei;
 
2178
                                                                Orientation orient = getMVSize(mv, x, y, x, y, conWid = new MutableDouble(0), conHei = new MutableDouble(0));
 
2179
                                                                if (canPlaceContact(np, newMetal, offendingMetal, offendingMetalColor, conX, conY, conWid.doubleValue(), conHei.doubleValue(), orient, endA))
 
2180
                                                                {
 
2181
                                                                        // offending layer is already there, so via can be dropped from it
 
2182
                                                                        viaToPlace = mv;
 
2183
                                                                        viaToPlaceX = conX;   viaToPlaceY = conY;
 
2184
                                                                        viaSizeX = conWid.doubleValue(); viaSizeY = conHei.doubleValue();
 
2185
                                                                        viaOrient = orient;
 
2186
                                                                        break;
 
2187
                                                                }
 
2188
                                                        }
 
2189
 
 
2190
                                                        index += dir;
 
2191
                                                        if (hor)
 
2192
                                                        {
 
2193
                                                                if (index < 0 || index >= gridLocationsY[newMetal].length) break;
 
2194
                                                                conY = gridLocationsY[newMetal][index].getCoordinate();
 
2195
                                                        } else
 
2196
                                                        {
 
2197
                                                                if (index < 0 || index >= gridLocationsX[newMetal].length) break;
 
2198
                                                                conX = gridLocationsX[newMetal][index].getCoordinate();
 
2199
                                                        }
 
2200
                                                }
 
2201
                                                if (viaToPlace == null)
 
2202
                                                {
 
2203
                                                        // heading away from goal (last resort)
 
2204
                                                        dir = -dir;
 
2205
                                                        index = startIndex + dir;
 
2206
                                                        for(;;)
 
2207
                                                        {
 
2208
                                                                newMetalColor = (hor ? gridLocationsY[newMetal][index].getMaskNum() : gridLocationsX[newMetal][index].getMaskNum());
 
2209
                                                                for (MetalVia mv : mvs)
 
2210
                                                                {
 
2211
                                                                        if (mv.horMetal == offendingMetal && mv.verMetal == newMetal)
 
2212
                                                                        {
 
2213
                                                                                if (mv.horMetalColor != offendingMetalColor || mv.verMetalColor != newMetalColor) continue;
 
2214
                                                                        } else if (mv.verMetal == offendingMetal && mv.horMetal == newMetal)
 
2215
                                                                        {
 
2216
                                                                                if (mv.verMetalColor != offendingMetalColor || mv.horMetalColor != newMetalColor) continue;
 
2217
                                                                        }
 
2218
                                                                        PrimitiveNode np = mv.via;
 
2219
                                                                        MutableDouble conWid, conHei;
 
2220
                                                                        Orientation orient = getMVSize(mv, x, y, x, y, conWid = new MutableDouble(0), conHei = new MutableDouble(0));
 
2221
                                                                        if (canPlaceContact(np, newMetal, offendingMetal, offendingMetalColor, conX, conY, conWid.doubleValue(), conHei.doubleValue(), orient, endA))
 
2222
                                                                        {
 
2223
                                                                                // offending layer is already there, so via can be dropped from it
 
2224
                                                                                viaToPlace = mv;
 
2225
                                                                                viaToPlaceX = conX;   viaToPlaceY = conY;
 
2226
                                                                                viaSizeX = conWid.doubleValue(); viaSizeY = conHei.doubleValue();
 
2227
                                                                                viaOrient = orient;
 
2228
                                                                                break;
 
2229
                                                                        }
 
2230
                                                                }
 
2231
                                                                if (viaToPlace != null) break;
 
2232
 
 
2233
                                                                index += dir;
 
2234
                                                                if (hor)
 
2235
                                                                {
 
2236
                                                                        if (index < 0 || index >= gridLocationsY[newMetal].length) break;
 
2237
                                                                        conY = gridLocationsY[newMetal][index].getCoordinate();
 
2238
                                                                } else
 
2239
                                                                {
 
2240
                                                                        if (index < 0 || index >= gridLocationsX[newMetal].length) break;
 
2241
                                                                        conX = gridLocationsX[newMetal][index].getCoordinate();
 
2242
                                                                }                                                                       
 
2243
                                                        }
 
2244
                                                }
 
2245
                                        } else
 
2246
                                        {
 
2247
                                                SeaOfGatesTrack sogt;
 
2248
                                                if (hor)
 
2249
                                                {
 
2250
                                                        sogt = getClosestYGrid(newMetal, conY);
 
2251
                                                } else
 
2252
                                                {
 
2253
                                                        sogt = getClosestXGrid(newMetal, conX);
 
2254
                                                }
 
2255
                                                newMetalColor = sogt.getMaskNum();
 
2256
 
 
2257
                                                // no forced gridding: just find a via at this coordinate
 
2258
                                                for (MetalVia mv : mvs)
 
2259
                                                {
 
2260
                                                        if (mv.horMetal == offendingMetal && mv.verMetal == newMetal)
 
2261
                                                        {
 
2262
                                                                if (mv.horMetalColor != offendingMetalColor || mv.verMetalColor != newMetalColor) continue;
 
2263
                                                        } else if (mv.verMetal == offendingMetal && mv.horMetal == newMetal)
 
2264
                                                        {
 
2265
                                                                if (mv.verMetalColor != offendingMetalColor || mv.horMetalColor != newMetalColor) continue;
 
2266
                                                        }
 
2267
                                                        PrimitiveNode np = mv.via;
 
2268
                                                        MutableDouble conWid, conHei;
 
2269
                                                        Orientation orient = getMVSize(mv, x, y, x, y, conWid = new MutableDouble(0), conHei = new MutableDouble(0));
 
2270
                                                        if (canPlaceContact(np, newMetal, offendingMetal, offendingMetalColor, conX, conY, conWid.doubleValue(), conHei.doubleValue(), orient, endA))
 
2271
                                                        {
 
2272
                                                                // offending layer is already there, so via can be dropped from it
 
2273
                                                                viaToPlace = mv;
 
2274
                                                                viaToPlaceX = conX;   viaToPlaceY = conY;
 
2275
                                                                viaSizeX = conWid.doubleValue(); viaSizeY = conHei.doubleValue();
 
2276
                                                                viaOrient = orient;
 
2277
                                                                break;
 
2278
                                                        }
 
2279
                                                }
 
2280
                                        }
 
2281
                                        if (viaToPlace != null)
 
2282
                                        {
 
2283
                                                String msg = "Route '" + routeName + "' at (" + TextUtils.formatDistance(pt.getX()) + "," +
 
2284
                                                        TextUtils.formatDistance(pt.getY()) + ") from port " + pi.getPortProto().getName() + " on node " +
 
2285
                                                        describe(pi.getNodeInst()) + " is disallowed on Metal " + (offendingMetal+1) + " so inserting " +
 
2286
                                                        viaToPlace.via.describe(false);
 
2287
                                                if (!DBMath.areEquals(pt.getX(), viaToPlaceX) || !DBMath.areEquals(pt.getY(), viaToPlaceY))
 
2288
                                                                msg += " at (" + TextUtils.formatDistance(viaToPlaceX) + "," + TextUtils.formatDistance(viaToPlaceY) + ")";
 
2289
                                                msg += " and routing from Metal " + (newMetal+1);
 
2290
                                                warn(msg);
 
2291
                                                if (endA)
 
2292
                                                {
 
2293
                                                        double dX = viaToPlaceX-aX, dY = viaToPlaceY-aY;
 
2294
                                                        aX = viaToPlaceX;
 
2295
                                                        aY = viaToPlaceY;
 
2296
                                                        Point[] pts = aPoly.getPoints();
 
2297
                                                        for(int i=0; i<pts.length; i++)
 
2298
                                                                pts[i].setLocation(pts[i].getX()+dX, pts[i].getY()+dY);
 
2299
                                                        aRect.setRect(aX, aY, 0, 0);
 
2300
//                                                      aRect.setRect(aRect.getMinX()+dX, aRect.getMinY()+dY, aRect.getWidth(), aRect.getHeight());
 
2301
                                                        double aLX = getLowerXGrid(aZ, aRect.getMinX()).getCoordinate();
 
2302
                                                        double aHX = getUpperXGrid(aZ, aRect.getMaxX()).getCoordinate();
 
2303
                                                        double aLY = getLowerYGrid(aZ, aRect.getMinY()).getCoordinate();
 
2304
                                                        double aHY = getUpperYGrid(aZ, aRect.getMaxY()).getCoordinate();
 
2305
                                                        aRectGridded = FixpRectangle.from(new Rectangle2D.Double(aLX, aLY, aHX-aLX, aHY-aLY));  
 
2306
                                                        aZ = newMetal;
 
2307
                                                        aC = newMetalColor;
 
2308
                                                        jumpBound = new Rectangle2D.Double(Math.min(aX, bX), Math.min(aY, bY), Math.abs(aX-bX), Math.abs(aY-bY));
 
2309
                                                        replaceA = viaToPlace;
 
2310
                                                        replaceAZ = offendingMetal;
 
2311
                                                        if (offendingMetalColor > 0)
 
2312
                                                                replaceAC = offendingMetalColor-1;
 
2313
 
 
2314
                                                        // reset taper width on this end since contact will be placed
 
2315
                                                        aTaperWid = getUntaperedArcWidth(newMetal);
 
2316
                                                        aTaperLen = -1;
 
2317
                                                } else
 
2318
                                                {
 
2319
                                                        double dX = viaToPlaceX-bX, dY = viaToPlaceY-bY;
 
2320
                                                        bX = viaToPlaceX;
 
2321
                                                        bY = viaToPlaceY;
 
2322
                                                        Point[] pts = bPoly.getPoints();
 
2323
                                                        for(int i=0; i<pts.length; i++)
 
2324
                                                                pts[i].setLocation(pts[i].getX()+dX, pts[i].getY()+dY);
 
2325
                                                        bRect.setRect(bX, bY, 0, 0);
 
2326
//                                                      bRect.setRect(bRect.getMinX()+dX, bRect.getMinY()+dY, bRect.getWidth(), bRect.getHeight());
 
2327
                                                        double bLX = getLowerXGrid(bZ, bRect.getMinX()).getCoordinate();
 
2328
                                                        double bHX = getUpperXGrid(bZ, bRect.getMaxX()).getCoordinate();
 
2329
                                                        double bLY = getLowerYGrid(bZ, bRect.getMinY()).getCoordinate();
 
2330
                                                        double bHY = getUpperYGrid(bZ, bRect.getMaxY()).getCoordinate();
 
2331
                                                        bRectGridded = FixpRectangle.from(new Rectangle2D.Double(bLX, bLY, bHX-bLX, bHY-bLY));
 
2332
                                                        bZ = newMetal;
 
2333
                                                        bC = newMetalColor;
 
2334
                                                        jumpBound = new Rectangle2D.Double(Math.min(aX, bX), Math.min(aY, bY), Math.abs(aX-bX), Math.abs(aY-bY));
 
2335
                                                        replaceB = viaToPlace;
 
2336
                                                        replaceBZ = offendingMetal;
 
2337
                                                        if (offendingMetalColor > 0)
 
2338
                                                                replaceBC = offendingMetalColor-1;
 
2339
 
 
2340
                                                        // reset taper width on this end since contact will be placed
 
2341
                                                        bTaperWid = getUntaperedArcWidth(newMetal);
 
2342
                                                        bTaperLen = -1;
 
2343
                                                }
 
2344
 
 
2345
                                                // add contact to blockages
 
2346
                                                NodeInst dummyNi = NodeInst.makeDummyInstance(viaToPlace.via, ep, EPoint.fromLambda(viaToPlaceX, viaToPlaceY),
 
2347
                                                        viaSizeX, viaSizeY, viaOrient);
 
2348
                                                Poly[] conPolys = tech.getShapeOfNode(dummyNi);
 
2349
                                                FixpTransform trans = null;
 
2350
                                                if (viaOrient != Orientation.IDENT) trans = dummyNi.rotateOut();
 
2351
                                                for (int p = 0; p < conPolys.length; p++)
 
2352
                                                {
 
2353
                                                        Poly conPoly = conPolys[p];
 
2354
                                                        Layer conLayer = conPoly.getLayer();
 
2355
                                                        if (trans != null) conPoly.transform(trans);
 
2356
                                                        Rectangle2D conRect = conPoly.getBounds2D();
 
2357
                                                        Layer.Function fun = conLayer.getFunction();
 
2358
                                                        if (fun.isMetal())
 
2359
                                                        {
 
2360
                                                                addRectangle(conRect, conLayer, netID, false, false);
 
2361
                                                        } else if (fun.isContact())
 
2362
                                                        {
 
2363
                                                                addVia(ERectangle.fromLambda(conRect), conLayer, netID, false);
 
2364
                                                        }
 
2365
                                                }
 
2366
                                                return false;
 
2367
                                        }
 
2368
                                }
 
2369
                        }
 
2370
 
 
2371
                        // cannot place contact or use existing layers, give an error
 
2372
                        String msg = "Route '" + routeName +  "' at (" + TextUtils.formatDistance(pt.getX()) + "," + TextUtils.formatDistance(pt.getY()) +
 
2373
                                ") from port " + pi.getPortProto().getName() + " on node " + describe(pi.getNodeInst()) + " cannot connect";
 
2374
                        if (sogp.isContactAllowedDownToAvoidedLayer() || sogp.isContactAllowedUpToAvoidedLayer())
 
2375
                        {
 
2376
                                msg += " (allowed to go";
 
2377
                                if (sogp.isContactAllowedDownToAvoidedLayer())
 
2378
                                {
 
2379
                                        if (sogp.isContactAllowedUpToAvoidedLayer()) msg += " up/down"; else msg += " down";
 
2380
                                } else if (sogp.isContactAllowedUpToAvoidedLayer()) msg += " up";
 
2381
                                msg += " one layer)";
 
2382
                        }
 
2383
 
 
2384
                        if (whatWasChecked.size() > 0)
 
2385
                        {
 
2386
                                boolean first = true;
 
2387
                                for(Integer m : whatWasChecked.keySet())
 
2388
                                {
 
2389
                                        if (first) msg += " because"; else msg += " and";
 
2390
                                        first = false;
 
2391
                                        java.awt.Point invalidColors = contactInvalidColors.get(m);
 
2392
                                        if (invalidColors != null)
 
2393
                                        {
 
2394
                                                msg += " no contact exists from metal-" + (realOffendingMetal+1) + " mask color " + invalidColors.x +
 
2395
                                                        " to metal-" + (m.intValue() + 1) + " mask color " + invalidColors.y;
 
2396
                                        } else
 
2397
                                        {
 
2398
                                                msg += " contact(s) cannot be placed:";
 
2399
                                                List<PrimitiveNode> contacts = whatWasChecked.get(m);
 
2400
                                                for(PrimitiveNode pNp : contacts) msg += " " + pNp.describe(false);
 
2401
                                        }
 
2402
                                }
 
2403
                        } else
 
2404
                        {
 
2405
                                 msg += " because all connecting layers have been prevented by Routing Preferences";
 
2406
                        }
 
2407
                        error(msg);
 
2408
                        List<PolyBase> polyList = new ArrayList<PolyBase>();
 
2409
                        polyList.add(new PolyBase(pt.getX(), pt.getY(), 0, 0));
 
2410
                        errorLogger.logMessageWithLines(msg, polyList, null, cell, 0, true);
 
2411
                        return true;
 
2412
                }
 
2413
 
 
2414
                /**
 
2415
                 * Method to determine the width of tapers.
 
2416
                 * Tapers are as wide as the metal at the end of the route.
 
2417
                 * @param pi the PortInst at the end of the route.
 
2418
                 * @param metalNo the metal layer (0-based) at the end of the route.
 
2419
                 * @return the taper width to use for that end of the route.
 
2420
                 */
 
2421
                private double getTaperWidth(PortInst pi, int metalNo)
 
2422
                {
 
2423
                        PortProto pp = pi.getPortProto();
 
2424
                        NodeInst ni = pi.getNodeInst();
 
2425
                        FixpTransform trans = ni.rotateOut();
 
2426
                        while (ni.isCellInstance())
 
2427
                        {
 
2428
                                Export e = (Export)pp;
 
2429
                                ni = e.getOriginalPort().getNodeInst();
 
2430
                                pp = e.getOriginalPort().getPortProto();
 
2431
                                trans.concatenate(ni.rotateOut());
 
2432
                        }
 
2433
                        Poly[] polys = ni.getProto().getTechnology().getShapeOfNode(ni);
 
2434
                        for(int i=0; i<polys.length; i++)
 
2435
                        {
 
2436
                                Poly poly = polys[i];
 
2437
                                boolean found = false;
 
2438
                                for(int j=0; j<metalLayers[metalNo].length; j++)
 
2439
                                        if (metalLayers[metalNo][j] == poly.getLayer()) { found = true;  break; }
 
2440
                                if (!found) continue;
 
2441
                                poly.transform(trans);
 
2442
                                FixpRectangle rect = poly.getBounds2D();
 
2443
                                boolean hor = true;
 
2444
                                if (sogp.isForceHorVer())
 
2445
                                {
 
2446
                                        if (sogp.isHorizontalEven())
 
2447
                                        {
 
2448
                                                if ((metalNo%2) == 0) hor = false;
 
2449
                                        } else
 
2450
                                        {
 
2451
                                                if ((metalNo%2) != 0) hor = false;
 
2452
                                        }
 
2453
                                        if (hor) return rect.getHeight();
 
2454
                                        return rect.getWidth();
 
2455
                                } else
 
2456
                                {
 
2457
                                        // choose narrowest dimension for taper width
 
2458
                                        return Math.min(rect.getWidth(), rect.getHeight());
 
2459
                                }
 
2460
                        }
 
2461
                        return getUntaperedArcWidth(metalNo);
 
2462
                }
 
2463
 
 
2464
                public void makeWavefronts()
1522
2465
                {
1523
2466
                        // make two wavefronts going in both directions
1524
 
                        Wavefront dirAtoB = new Wavefront(this, aPi, aRect, aX, aY, aZ, OFFSETENDA, bPi, bRect, bRectGridded, bX, bY, bZ, OFFSETENDB, 1, "a->b");
1525
 
                        Wavefront dirBtoA = new Wavefront(this, bPi, bRect, bX, bY, bZ, OFFSETENDB, aPi, aRect, aRectGridded, aX, aY, aZ, OFFSETENDA, -1, "b->a");
 
2467
                        dirAtoB = new Wavefront(this, aPi, aRect, aX, aY, aZ, aC, aTaperLen, BLOCKAGEENDA,
 
2468
                                bPi, bRect, bRectGridded, bX, bY, bZ, bC, bTaperLen, 1, "a->b",
 
2469
                                        debuggingRouteFromA != null && debuggingRouteFromA.booleanValue());
 
2470
                        dirBtoA = new Wavefront(this, bPi, bRect, bX, bY, bZ, bC, bTaperLen, BLOCKAGEENDB,
 
2471
                                aPi, aRect, aRectGridded, aX, aY, aZ, aC, aTaperLen, -1, "b->a",
 
2472
                                        debuggingRouteFromA != null && !debuggingRouteFromA.booleanValue());
1526
2473
 
1527
2474
//                      if (ANYPOINTONDESTINATION)
1528
2475
//                      {
1529
2476
//                              // mark the blockages with the two ends of the route
1530
 
//                              growPoint(aX, aY, aZ, netID+OFFSETENDA, true);
1531
 
//                              growPoint(bX, bY, bZ, netID+OFFSETENDB, true);
 
2477
//                              growPoint(aX, aY, aZ, netID+BLOCKAGEENDA);
 
2478
//                              growPoint(bX, bY, bZ, netID+BLOCKAGEENDB);
1532
2479
//                      }
1533
 
                        return new Wavefront[] { dirAtoB, dirBtoA };
1534
2480
                }
1535
2481
 
1536
2482
                public void setBatchInfo(RouteBatch batch, int routeInBatch)
1559
2505
                        theseNetIDs.add(netID);
1560
2506
                }
1561
2507
 
1562
 
                public double getArcWidth(int metNum)
 
2508
                /**
 
2509
                 * Method to determine whether a given layer of metal runs on 2X width wires or not.
 
2510
                 * @param metNum the 0-based layer of metal.
 
2511
                 * @return true if the layer of metal runs on 2X width wires.
 
2512
                 */
 
2513
                public boolean is2X(int metNum, double fX, double fY, double tX, double tY)
 
2514
                {
 
2515
                        if (size2X[metNum] != 0)
 
2516
                        {
 
2517
                                double wid = getArcWidth(metNum, fX, fY, tX, tY);
 
2518
                                if (wid >= size2X[metNum]) return true;
 
2519
                        }
 
2520
                        return false;
 
2521
                }
 
2522
 
 
2523
                /**
 
2524
                 * Method to determine the width to use for an arc.
 
2525
                 * @param metNum the metal number of the arc.
 
2526
                 * @param fX X coordinate of one point on the arc.
 
2527
                 * @param fY Y coordinate of one point on the arc.
 
2528
                 * @param tX X coordinate of another point on the arc.
 
2529
                 * @param tY Y coordinate of another point on the arc.
 
2530
                 * @return the width to use for that arc.
 
2531
                 */
 
2532
                public double getArcWidth(int metNum, double fX, double fY, double tX, double tY)
 
2533
                {
 
2534
                        // "hor" is null if arc can run either way
 
2535
                        Boolean hor = null;
 
2536
                        if (sogp.isForceHorVer())
 
2537
                        {
 
2538
                                hor = Boolean.TRUE;
 
2539
                                if (sogp.isHorizontalEven())
 
2540
                                {
 
2541
                                        if ((metNum%2) == 0) hor = Boolean.FALSE;
 
2542
                                } else
 
2543
                                {
 
2544
                                        if ((metNum%2) != 0) hor = Boolean.FALSE;
 
2545
                                }
 
2546
                        }
 
2547
 
 
2548
                        // see if either point could be a taper from the "a" end
 
2549
                        if (aTaperLen >= 0 && aZ == metNum)
 
2550
                        {
 
2551
                                if (hor == null || hor.booleanValue())
 
2552
                                {
 
2553
                                        if (fY == aY && Math.abs(fX-aX) < aTaperLen) return aTaperWid;
 
2554
                                        if (tY == aY && Math.abs(tX-aX) < aTaperLen) return aTaperWid;
 
2555
                                }
 
2556
                                if (hor == null || !hor.booleanValue())
 
2557
                                {
 
2558
                                        if (fX == aX && Math.abs(fY-aY) < aTaperLen) return aTaperWid;
 
2559
                                        if (tX == aX && Math.abs(tY-aY) < aTaperLen) return aTaperWid;
 
2560
                                }
 
2561
                        }
 
2562
 
 
2563
                        // see if either point could be a taper from the "b" end
 
2564
                        if (bTaperLen >= 0 && bZ == metNum)
 
2565
                        {
 
2566
                                if (hor == null || hor.booleanValue())
 
2567
                                {
 
2568
                                        if (fY == bY && Math.abs(fX-bX) < bTaperLen) return bTaperWid;
 
2569
                                        if (tY == bY && Math.abs(tX-bX) < bTaperLen) return bTaperWid;
 
2570
                                }
 
2571
                                if (hor == null || !hor.booleanValue())
 
2572
                                {
 
2573
                                        if (fX == bX && Math.abs(fY-bY) < bTaperLen) return bTaperWid;
 
2574
                                        if (tX == bX && Math.abs(tY-bY) < bTaperLen) return bTaperWid;
 
2575
                                }
 
2576
                        }
 
2577
 
 
2578
                        // not a taper: use the default widths
 
2579
                        return getUntaperedArcWidth(metNum);
 
2580
                }
 
2581
 
 
2582
                public double getUntaperedArcWidth(int metNum)
1563
2583
                {
1564
2584
                        if (overrideMetalWidth != null) return overrideMetalWidth[metNum];
1565
 
                        double width = Math.max(metalArcs[metNum].getDefaultLambdaBaseWidth(ep), minWidth);
 
2585
                        double width = Math.max(maxDefArcWidth[metNum], minWidth);
1566
2586
                        return width;
1567
2587
                }
1568
2588
 
1576
2596
                public double[] getSpacingRule(int layer, double width, double length)
1577
2597
                {
1578
2598
                        // use override spacing if specified
1579
 
                        if (overrideMetalSpacingX != null) return new double[] {overrideMetalSpacingX[layer], overrideMetalSpacingY[layer]};
 
2599
                        if (overrideMetalSpacings[layer] != null) return overrideMetalSpacings[layer];
1580
2600
 
1581
2601
                        // use default width if none specified
1582
 
                        if (width < 0) width = metalArcs[layer].getDefaultLambdaBaseWidth(ep);
 
2602
                        if (width < 0) width = maxDefArcWidth[layer];
1583
2603
                        if (length < 0) length = 50;
1584
2604
 
1585
2605
                        // see if the rule is cached
1595
2615
                                }
1596
2616
                        }
1597
2617
                        Double len = Double.valueOf(length);
1598
 
                        double[] value = widMap.get(len);
1599
 
                        if (value == null)
 
2618
                        double[] value = new double[2];
 
2619
                        double[] cachedValue = widMap.get(len);
 
2620
                        if (cachedValue != null)
 
2621
                        {
 
2622
                                value[0] = cachedValue[0];
 
2623
                                value[1] = cachedValue[1];
 
2624
                        } else
1600
2625
                        {
1601
2626
                                // rule not cached: compute it
1602
 
                                Layer lay = metalLayers[layer];
1603
 
                                DRCTemplate rule = DRC.getSpacingRule(lay, null, lay, null, false, -1, width, length);
1604
 
                                double x = 0, y = 0;
1605
 
                                if (rule != null)
 
2627
                                value[0] = 0;   value[1] = -1;
 
2628
                                for(int c=0; c<metalLayers[layer].length; c++)
1606
2629
                                {
1607
 
                                        x = rule.getValue(0);
1608
 
                                        if (rule.getNumValues() <= 1) y = x; else
1609
 
                                                y = rule.getValue(1);
 
2630
                                        Layer lay = metalLayers[layer][c];
 
2631
                                        DRCTemplate rule = DRC.getSpacingRule(lay, null, lay, null, false, -1, width, length);
 
2632
                                        if (rule != null)
 
2633
                                        {
 
2634
                                                value[0] = Math.max(value[0], rule.getValue(0));
 
2635
                                                if (rule.getNumValues() > 1) value[1] = Math.max(value[1], rule.getValue(1));
 
2636
                                        }
1610
2637
                                }
1611
 
                                value = new double[] {x, y};
 
2638
                                if (value[1] < 0) value[1] = value[0];
1612
2639
                                widMap.put(len, value);
1613
2640
                        }
 
2641
 
 
2642
                        // handle overrides
 
2643
                        if (overrideMetalSpacingX != null) value[0] = overrideMetalSpacingX[layer];
 
2644
                        if (overrideMetalSpacingY != null) value[1] = overrideMetalSpacingY[layer];
1614
2645
                        return value;
1615
2646
                }
1616
2647
 
1686
2717
                public boolean checkEndSurround()
1687
2718
                {
1688
2719
                        // determine "A" end surround
1689
 
                        double fromMetalSpacing = getArcWidth(aZ) / 2;
1690
 
                        double[] fromSurround = getSpacingRule(aZ, metalArcs[aZ].getDefaultLambdaBaseWidth(ep), -1);
 
2720
                        double fromMetalSpacing = getArcWidth(aZ, aX, aY, aX, aY) / 2;
 
2721
                        double[] fromSurround = getSpacingRule(aZ, maxDefArcWidth[aZ], -1);
1691
2722
 
1692
2723
                        // see if "A" end access is blocked
1693
2724
                        SOGBound block = getMetalBlockage(netID, aZ, fromMetalSpacing, fromMetalSpacing, fromSurround, aX, aY);
1694
 
                        if (block != null)
 
2725
                        if (block != null && !sogp.isGridForced(primaryMetalArc[aZ]))
1695
2726
                        {
1696
 
                                // see if gridding caused the blockage
1697
 
                                block = getMetalBlockage(netID, aZ, fromMetalSpacing, fromMetalSpacing, fromSurround, aX, aY);
1698
 
                                if (block != null)
 
2727
                                // ungridded center location still blocked: see if port has nonzero area and other places in it are free
 
2728
                                Rectangle2D fromRect = aPoly.getBounds2D();
 
2729
                                double stepSize = fromMetalSpacing + Math.max(fromSurround[0], fromSurround[1]);
 
2730
                                if (stepSize > 0 && (fromRect.getWidth() > 0 || fromRect.getHeight() > 0))
1699
2731
                                {
1700
 
                                        // ungridded center location still blocked: see if port has nonzero area and other places in it are free
1701
 
                                        Rectangle2D fromRect = aPoly.getBounds2D();
1702
 
                                        double stepSize = fromMetalSpacing + Math.max(fromSurround[0], fromSurround[1]);
1703
 
                                        if (stepSize > 0 && (fromRect.getWidth() > 0 || fromRect.getHeight() > 0))
 
2732
                                        for(double x = fromRect.getMinX(); x <= fromRect.getMaxX(); x += stepSize)
1704
2733
                                        {
1705
 
                                                for(double x = fromRect.getMinX(); x <= fromRect.getMaxX(); x += stepSize)
 
2734
                                                for(double y = fromRect.getMinY(); y <= fromRect.getMaxY(); y += stepSize)
1706
2735
                                                {
1707
 
                                                        for(double y = fromRect.getMinY(); y <= fromRect.getMaxY(); y += stepSize)
 
2736
                                                        SOGBound stepBlock = getMetalBlockage(netID, aZ, fromMetalSpacing, fromMetalSpacing, fromSurround, x, y);
 
2737
                                                        if (stepBlock == null)
1708
2738
                                                        {
1709
 
                                                                SOGBound stepBlock = getMetalBlockage(netID, aZ, fromMetalSpacing, fromMetalSpacing, fromSurround, x, y);
1710
 
                                                                if (stepBlock == null)
1711
 
                                                                {
1712
 
                                                                        aX = x;   aY = y;
1713
 
                                                                        block = null;
1714
 
                                                                        break;
1715
 
                                                                }
 
2739
                                                                aX = x;   aY = y;
 
2740
                                                                block = null;
 
2741
                                                                break;
1716
2742
                                                        }
1717
 
                                                        if (block == null) break;
1718
2743
                                                }
1719
 
                                        }
1720
 
                                        if (block != null)
1721
 
                                        {
1722
 
                                                String errorMsg = "Cannot route from port " + aPi.getPortProto().getName()
1723
 
                                                        + " of node " + describe(aPi.getNodeInst()) + " at ("
1724
 
                                                        + formatDistance(aX) + "," + formatDistance(aY)
1725
 
                                                        + ") because it is blocked on layer " + metalLayers[aZ].getName()
1726
 
                                                        + " [needs " + formatDistance(fromMetalSpacing + Math.max(fromSurround[0], fromSurround[1]))
1727
 
                                                        + " all around, blockage is "
1728
 
                                                        + formatDistance(block.getBounds().getMinX()) + "<=X<="
1729
 
                                                        + formatDistance(block.getBounds().getMaxX()) + " and "
1730
 
                                                        + formatDistance(block.getBounds().getMinY()) + "<=Y<="
1731
 
                                                        + formatDistance(block.getBounds().getMaxY())
1732
 
//                                                      + ", block on net " + block.getNetID() + " but this net is " + this.netID
1733
 
                                                        + "]";
1734
 
                                                if (reroute) errorMsg = "(Retry) " + errorMsg;
1735
 
                                                error(errorMsg);
1736
 
                                                List<PolyBase> polyList = new ArrayList<PolyBase>();
1737
 
                                                polyList.add(new PolyBase(aX, aY, (fromMetalSpacing + fromSurround[0]) * 2,
1738
 
                                                        (fromMetalSpacing + fromSurround[1]) * 2));
1739
 
                                                polyList.add(new PolyBase(block.getBounds()));
1740
 
                                                List<EPoint> lineList = new ArrayList<EPoint>();
1741
 
                                                lineList.add(EPoint.fromLambda(block.getBounds().getMinX(), block.getBounds().getMinY()));
1742
 
                                                lineList.add(EPoint.fromLambda(block.getBounds().getMaxX(), block.getBounds().getMaxY()));
1743
 
                                                lineList.add(EPoint.fromLambda(block.getBounds().getMinX(), block.getBounds().getMaxY()));
1744
 
                                                lineList.add(EPoint.fromLambda(block.getBounds().getMaxX(), block.getBounds().getMinY()));
1745
 
                                                errorLogger.logMessageWithLines(errorMsg, polyList, lineList, cell, 0, true);
1746
 
                                                return true;
1747
 
                                        }
 
2744
                                                if (block == null) break;
 
2745
                                        }
 
2746
                                }
 
2747
                                if (block != null)
 
2748
                                {
 
2749
                                        String errorMsg = "Cannot route from port " + aPi.getPortProto().getName()
 
2750
                                                + " of node " + describe(aPi.getNodeInst()) + " at ("
 
2751
                                                + TextUtils.formatDistance(aX) + "," + TextUtils.formatDistance(aY)
 
2752
                                                + ") because it is blocked on layer " + describeMetal(aZ,aC)
 
2753
                                                + " [needs " + TextUtils.formatDistance(fromMetalSpacing + Math.max(fromSurround[0], fromSurround[1]))
 
2754
                                                + " all around, blockage is "
 
2755
                                                + TextUtils.formatDistance(block.getBounds().getMinX()) + "<=X<="
 
2756
                                                + TextUtils.formatDistance(block.getBounds().getMaxX()) + " and "
 
2757
                                                + TextUtils.formatDistance(block.getBounds().getMinY()) + "<=Y<="
 
2758
                                                + TextUtils.formatDistance(block.getBounds().getMaxY())
 
2759
                                                + "]";
 
2760
                                        if (reroute) errorMsg = "(Retry) " + errorMsg;
 
2761
                                        error(errorMsg);
 
2762
                                        List<PolyBase> polyList = new ArrayList<PolyBase>();
 
2763
                                        polyList.add(new PolyBase(aX, aY, (fromMetalSpacing + fromSurround[0]) * 2,
 
2764
                                                (fromMetalSpacing + fromSurround[1]) * 2));
 
2765
                                        polyList.add(new PolyBase(block.getBounds()));
 
2766
                                        List<EPoint> lineList = new ArrayList<EPoint>();
 
2767
                                        lineList.add(EPoint.fromLambda(block.getBounds().getMinX(), block.getBounds().getMinY()));
 
2768
                                        lineList.add(EPoint.fromLambda(block.getBounds().getMaxX(), block.getBounds().getMaxY()));
 
2769
                                        lineList.add(EPoint.fromLambda(block.getBounds().getMinX(), block.getBounds().getMaxY()));
 
2770
                                        lineList.add(EPoint.fromLambda(block.getBounds().getMaxX(), block.getBounds().getMinY()));
 
2771
                                        errorLogger.logMessageWithLines(errorMsg, polyList, lineList, cell, 0, true);
 
2772
                                        return true;
1748
2773
                                }
1749
2774
                        }
1750
2775
 
1751
2776
                        // determine "B" end surround
1752
 
                        double toMetalSpacing = getArcWidth(bZ) / 2;
1753
 
                        double[] toSurround = getSpacingRule(bZ, metalArcs[bZ].getDefaultLambdaBaseWidth(ep), -1);
 
2777
                        double toMetalSpacing = getArcWidth(bZ, bX, bY, bX, bY) / 2;
 
2778
                        double[] toSurround = getSpacingRule(bZ, maxDefArcWidth[bZ], -1);
1754
2779
 
1755
2780
                        // see if "B" end access is blocked
1756
2781
                        block = getMetalBlockage(netID, bZ, toMetalSpacing, toMetalSpacing, toSurround, bX, bY);
1757
 
                        if (block != null)
 
2782
                        if (block != null && !sogp.isGridForced(primaryMetalArc[bZ]))
1758
2783
                        {
1759
 
                                // see if gridding caused the blockage
1760
 
                                block = getMetalBlockage(netID, bZ, toMetalSpacing, toMetalSpacing, toSurround, bX, bY);
1761
 
                                if (block != null)
 
2784
                                // ungridded center location still blocked: see if port has nonzero area and other places in it are free
 
2785
                                Rectangle2D toRect = bPoly.getBounds2D();
 
2786
                                double stepSize = toMetalSpacing + Math.max(toSurround[0], toSurround[1]);
 
2787
                                if (stepSize > 0 && (toRect.getWidth() > 0 || toRect.getHeight() > 0))
1762
2788
                                {
1763
 
                                        // ungridded center location still blocked: see if port has nonzero area and other places in it are free
1764
 
                                        Rectangle2D toRect = bPoly.getBounds2D();
1765
 
                                        double stepSize = toMetalSpacing + Math.max(toSurround[0], toSurround[1]);
1766
 
                                        if (stepSize > 0 && (toRect.getWidth() > 0 || toRect.getHeight() > 0))
 
2789
                                        for(double x = toRect.getMinX(); x <= toRect.getMaxX(); x += stepSize)
1767
2790
                                        {
1768
 
                                                for(double x = toRect.getMinX(); x <= toRect.getMaxX(); x += stepSize)
 
2791
                                                for(double y = toRect.getMinY(); y <= toRect.getMaxY(); y += stepSize)
1769
2792
                                                {
1770
 
                                                        for(double y = toRect.getMinY(); y <= toRect.getMaxY(); y += stepSize)
 
2793
                                                        SOGBound stepBlock = getMetalBlockage(netID, bZ, toMetalSpacing, toMetalSpacing, toSurround, x, y);
 
2794
                                                        if (stepBlock == null)
1771
2795
                                                        {
1772
 
                                                                SOGBound stepBlock = getMetalBlockage(netID, bZ, toMetalSpacing, toMetalSpacing, toSurround, x, y);
1773
 
                                                                if (stepBlock == null)
1774
 
                                                                {
1775
 
                                                                        bX = x;   bY = y;
1776
 
                                                                        block = null;
1777
 
                                                                        break;
1778
 
                                                                }
 
2796
                                                                bX = x;   bY = y;
 
2797
                                                                block = null;
 
2798
                                                                break;
1779
2799
                                                        }
1780
 
                                                        if (block == null) break;
1781
2800
                                                }
1782
 
                                        }
1783
 
                                        if (block != null)
1784
 
                                        {
1785
 
                                                String errorMsg = "Cannot route to port " + bPi.getPortProto().getName()
1786
 
                                                        + " of node " + describe(bPi.getNodeInst()) + " at ("
1787
 
                                                        + formatDistance(bX) + "," + formatDistance(bY)
1788
 
                                                        + ") because it is blocked on layer " + metalLayers[bZ].getName()
1789
 
                                                        + " [needs " + formatDistance(toMetalSpacing + Math.max(toSurround[0], toSurround[1]))
1790
 
                                                        + " all around, blockage is "
1791
 
                                                        + formatDistance(block.getBounds().getMinX()) + "<=X<="
1792
 
                                                        + formatDistance(block.getBounds().getMaxX()) + " and "
1793
 
                                                        + formatDistance(block.getBounds().getMinY()) + "<=Y<="
1794
 
                                                        + formatDistance(block.getBounds().getMaxY())
1795
 
//                                                      + ", block on net " + block.getNetID() + " but this net is " + this.netID
1796
 
                                                        + "]";
1797
 
                                                if (reroute) errorMsg = "(Retry) " + errorMsg;
1798
 
                                                error(errorMsg);
1799
 
                                                List<PolyBase> polyList = new ArrayList<PolyBase>();
1800
 
                                                polyList.add(new PolyBase(bX, bY, (toMetalSpacing + toSurround[0]) * 2,
1801
 
                                                        (toMetalSpacing + toSurround[1]) * 2));
1802
 
                                                polyList.add(new PolyBase(block.getBounds()));
1803
 
                                                List<EPoint> lineList = new ArrayList<EPoint>();
1804
 
                                                lineList.add(EPoint.fromLambda(block.getBounds().getMinX(), block.getBounds().getMinY()));
1805
 
                                                lineList.add(EPoint.fromLambda(block.getBounds().getMaxX(), block.getBounds().getMaxY()));
1806
 
                                                lineList.add(EPoint.fromLambda(block.getBounds().getMinX(), block.getBounds().getMaxY()));
1807
 
                                                lineList.add(EPoint.fromLambda(block.getBounds().getMaxX(), block.getBounds().getMinY()));
1808
 
                                                errorLogger.logMessageWithLines(errorMsg, polyList, lineList, cell, 0, true);
1809
 
                                                return true;
1810
 
                                        }
 
2801
                                                if (block == null) break;
 
2802
                                        }
 
2803
                                }
 
2804
                                if (block != null)
 
2805
                                {
 
2806
                                        String errorMsg = "Cannot route to port " + bPi.getPortProto().getName()
 
2807
                                                + " of node " + describe(bPi.getNodeInst()) + " at ("
 
2808
                                                + TextUtils.formatDistance(bX) + "," + TextUtils.formatDistance(bY)
 
2809
                                                + ") because it is blocked on layer " + describeMetal(bZ,bC)
 
2810
                                                + " [needs " + TextUtils.formatDistance(toMetalSpacing + Math.max(toSurround[0], toSurround[1]))
 
2811
                                                + " all around, blockage is "
 
2812
                                                + TextUtils.formatDistance(block.getBounds().getMinX()) + "<=X<="
 
2813
                                                + TextUtils.formatDistance(block.getBounds().getMaxX()) + " and "
 
2814
                                                + TextUtils.formatDistance(block.getBounds().getMinY()) + "<=Y<="
 
2815
                                                + TextUtils.formatDistance(block.getBounds().getMaxY())
 
2816
                                                + "]";
 
2817
                                        if (reroute) errorMsg = "(Retry) " + errorMsg;
 
2818
                                        error(errorMsg);
 
2819
                                        List<PolyBase> polyList = new ArrayList<PolyBase>();
 
2820
                                        polyList.add(new PolyBase(bX, bY, (toMetalSpacing + toSurround[0]) * 2,
 
2821
                                                (toMetalSpacing + toSurround[1]) * 2));
 
2822
                                        polyList.add(new PolyBase(block.getBounds()));
 
2823
                                        List<EPoint> lineList = new ArrayList<EPoint>();
 
2824
                                        lineList.add(EPoint.fromLambda(block.getBounds().getMinX(), block.getBounds().getMinY()));
 
2825
                                        lineList.add(EPoint.fromLambda(block.getBounds().getMaxX(), block.getBounds().getMaxY()));
 
2826
                                        lineList.add(EPoint.fromLambda(block.getBounds().getMinX(), block.getBounds().getMaxY()));
 
2827
                                        lineList.add(EPoint.fromLambda(block.getBounds().getMaxX(), block.getBounds().getMinY()));
 
2828
                                        errorLogger.logMessageWithLines(errorMsg, polyList, lineList, cell, 0, true);
 
2829
                                        return true;
1811
2830
                                }
1812
2831
                        }
1813
2832
                        return false;
1818
2837
                        // initialize list of SOGBounds to extract
1819
2838
                        extractList = new HashMap<SOGBound,Integer>();
1820
2839
 
1821
 
                        // fill list from the two endpoints of the route
1822
 
                        growPoint(aX, aY, aZ, netID);
1823
 
                        growPoint(bX, bY, bZ, netID);
 
2840
                        // fill list from the first endpoint of the route
 
2841
                        MutableInteger miA = new MutableInteger(netID.intValue() | BLOCKAGEENDA);
 
2842
                        MutableInteger miB = new MutableInteger(netID.intValue() | BLOCKAGEENDB);
 
2843
                        growPoint(aX, aY, aZ, miA);
 
2844
 
 
2845
                        // iterate until the list is empty
 
2846
                        for(;;)
 
2847
                        {
 
2848
                                Iterator<SOGBound> it = extractList.keySet().iterator();
 
2849
                                if (!it.hasNext()) break;
 
2850
                                SOGBound sBound = it.next();
 
2851
                                Integer layerNumInt = extractList.get(sBound);
 
2852
                                extractList.remove(sBound);
 
2853
                                growArea(sBound, layerNumInt.intValue(), sBound.getNetID());
 
2854
                        }
 
2855
 
 
2856
                        // now fill list from the second endpoint, noting whether the routing is already done
 
2857
                        boolean alreadyDone = growPoint(bX, bY, bZ, miB);
 
2858
                        if (alreadyDone) alreadyRouted = true;
1824
2859
 
1825
2860
                        // add in blockage setting for any tap points on the spine
1826
2861
                        if (spineTaps != null)
1843
2878
                                SOGBound sBound = it.next();
1844
2879
                                Integer layerNumInt = extractList.get(sBound);
1845
2880
                                extractList.remove(sBound);
1846
 
                                growArea(sBound.bound, layerNumInt.intValue(), sBound.getNetID());
 
2881
                                growArea(sBound, layerNumInt.intValue(), sBound.getNetID());
1847
2882
                        }
1848
2883
                        extractList = null;
1849
2884
                }
1850
2885
 
1851
 
                private void growPoint(double x, double y, int layerNum, MutableInteger idNumber)
 
2886
                /**
 
2887
                 * Method to accumulate a list of blockage rectangles that are at a given coordinate.
 
2888
                 * @param x the X coordinate.
 
2889
                 * @param y the Y coordinate.
 
2890
                 * @param layerNum the metal layer number (0-based).
 
2891
                 * @param idNumber the network number being propagated.
 
2892
                 * @return true if this network number is already at the coordinate.
 
2893
                 */
 
2894
                private boolean growPoint(double x, double y, int layerNum, MutableInteger idNumber)
1852
2895
                {
1853
2896
                        Rectangle2D search = new Rectangle2D.Double(x, y, 0, 0);
1854
 
                        BlockageTree bTree = rTrees.getMetalTree(metalLayers[layerNum]);
1855
 
                        if (bTree.isEmpty()) return;
 
2897
                        BlockageTree bTree = rTrees.getMetalTree(primaryMetalLayer[layerNum]);
 
2898
                        if (bTree.isEmpty()) return false;
 
2899
                        boolean foundNet = false;
1856
2900
                        for (Iterator<SOGBound> sea = bTree.search(search); sea.hasNext();)
1857
2901
                        {
1858
2902
                                SOGBound sBound = sea.next();
 
2903
                                if (sBound.isUserSuppliedBlockage()) continue;
 
2904
                                if (!sBound.containsPoint(x, y)) continue;
1859
2905
                                if (sBound.getNetID() == null)
1860
2906
                                {
1861
2907
                                        sBound.setNetID(idNumber);
1867
2913
                                                        setProgressValue(blockagesFound, totalBlockages);
1868
2914
                                        }
1869
2915
                                        continue;
 
2916
                                } else
 
2917
                                {
 
2918
                                        if (sBound.isSameBasicNet(idNumber)) foundNet = true;
1870
2919
                                }
1871
2920
                                sBound.updateNetID(idNumber, netIDsByValue);
1872
2921
                        }
 
2922
                        return foundNet;
1873
2923
                }
1874
2924
 
1875
 
                private void growArea(Rectangle2D bound, int layerNum, MutableInteger idNumber)
 
2925
                private void growArea(SOGBound sBound, int layerNum, MutableInteger idNumber)
1876
2926
                {
1877
 
                        BlockageTree metalTree = rTrees.getMetalTree(metalLayers[layerNum]);
 
2927
                        BlockageTree metalTree = rTrees.getMetalTree(primaryMetalLayer[layerNum]);
 
2928
                        Rectangle2D bound = sBound.bound;
1878
2929
                        for (Iterator<SOGBound> sea = metalTree.search(bound); sea.hasNext(); )
1879
2930
                        {
1880
 
                                SOGBound sBound = sea.next();
1881
 
                                if (sBound.getNetID() == null)
1882
 
                                {
1883
 
                                        sBound.setNetID(idNumber);
1884
 
                                        if (extractList.get(sBound) == null)
 
2931
                                SOGBound subBound = sea.next();
 
2932
                                if (subBound.isUserSuppliedBlockage()) continue;
 
2933
                                if (sBound instanceof SOGPoly || subBound instanceof SOGPoly)
 
2934
                                {
 
2935
                                        // make sure they really intersect
 
2936
                                        if (!doesIntersect(sBound, subBound)) continue;
 
2937
                                }
 
2938
                                if (subBound.getNetID() == null)
 
2939
                                {
 
2940
                                        subBound.setNetID(idNumber);
 
2941
                                        if (extractList.get(subBound) == null)
1885
2942
                                        {
1886
 
                                                extractList.put(sBound, Integer.valueOf(layerNum));
 
2943
                                                extractList.put(subBound, Integer.valueOf(layerNum));
1887
2944
                                                blockagesFound++;
1888
2945
                                                if ((blockagesFound%100) == 0)
1889
2946
                                                        setProgressValue(blockagesFound, totalBlockages);
1890
2947
                                        }
1891
2948
                                        continue;
1892
2949
                                }
1893
 
                                sBound.updateNetID(idNumber, netIDsByValue);
 
2950
                                subBound.updateNetID(idNumber, netIDsByValue);
1894
2951
                        }
1895
2952
 
1896
2953
                        // look at vias on lower layer
1901
2958
                                {
1902
2959
                                        for (Iterator<SOGBound> sea = viaTree.search(bound); sea.hasNext(); )
1903
2960
                                        {
1904
 
                                                SOGVia sBound = (SOGVia)sea.next();
1905
 
                                                if (sBound.getNetID() == null)
1906
 
                                                {
1907
 
                                                        sBound.setNetID(idNumber);
1908
 
                                                        growPoint(sBound.loc.getX(), sBound.loc.getY(), layerNum-1, idNumber);
 
2961
                                                SOGVia subBound = (SOGVia)sea.next();
 
2962
                                                if (sBound instanceof SOGPoly)
 
2963
                                                {
 
2964
                                                        // make sure they really intersect
 
2965
                                                        if (!doesIntersect(sBound, subBound)) continue;
 
2966
                                                }
 
2967
                                                if (subBound.getNetID() == null)
 
2968
                                                {
 
2969
                                                        subBound.setNetID(idNumber);
 
2970
                                                        growPoint(subBound.getBounds().getCenterX(), subBound.getBounds().getCenterY(), layerNum-1, idNumber);
1909
2971
                                                        continue;
1910
2972
                                                }
1911
 
                                                sBound.updateNetID(idNumber, netIDsByValue);
 
2973
                                                subBound.updateNetID(idNumber, netIDsByValue);
1912
2974
                                        }
1913
2975
                                }
1914
2976
                        }
1919
2981
                                BlockageTree bTree = rTrees.getViaTree(viaLayers[layerNum]);
1920
2982
                                for (Iterator<SOGBound> sea = bTree.search(bound); sea.hasNext();)
1921
2983
                                {
1922
 
                                        SOGVia sBound = (SOGVia)sea.next();
1923
 
                                        if (sBound.getNetID() == null)
1924
 
                                        {
1925
 
                                                sBound.setNetID(idNumber);
1926
 
                                                growPoint(sBound.loc.getX(), sBound.loc.getY(), layerNum+1, idNumber);
1927
 
                                                continue;
1928
 
                                        }
1929
 
                                        sBound.updateNetID(idNumber, netIDsByValue);
1930
 
                                }
1931
 
                        }
 
2984
                                        SOGVia subBound = (SOGVia)sea.next();
 
2985
                                        if (sBound instanceof SOGPoly)
 
2986
                                        {
 
2987
                                                // make sure they really intersect
 
2988
                                                if (!doesIntersect(sBound, subBound)) continue;
 
2989
                                        }
 
2990
                                        if (subBound.getNetID() == null)
 
2991
                                        {
 
2992
                                                subBound.setNetID(idNumber);
 
2993
                                                growPoint(subBound.getBounds().getCenterX(), subBound.getBounds().getCenterY(), layerNum+1, idNumber);
 
2994
                                                continue;
 
2995
                                        }
 
2996
                                        subBound.updateNetID(idNumber, netIDsByValue);
 
2997
                                }
 
2998
                        }
 
2999
                }
 
3000
 
 
3001
                private boolean doesIntersect(SOGBound bound1, SOGBound bound2)
 
3002
                {
 
3003
                        // first see if the polygons are Manhattan
 
3004
                        if (!bound1.isManhattan() || !bound2.isManhattan()) return true;
 
3005
 
 
3006
                        EPoint[] points1;
 
3007
                        if (bound1 instanceof SOGPoly)
 
3008
                        {
 
3009
                                SOGPoly p = (SOGPoly)bound1;
 
3010
                                Point[] po = p.poly.getPoints();
 
3011
                                points1 = new EPoint[po.length];
 
3012
                                for(int i=0; i<po.length; i++) points1[i] = EPoint.fromLambda(po[i].getX(), po[i].getY());
 
3013
                        } else
 
3014
                        {
 
3015
                                points1 = new EPoint[5];
 
3016
                                points1[0] = EPoint.fromLambda(bound1.bound.getMinX(), bound1.bound.getMinY());
 
3017
                                points1[1] = EPoint.fromLambda(bound1.bound.getMinX(), bound1.bound.getMaxY());
 
3018
                                points1[2] = EPoint.fromLambda(bound1.bound.getMaxX(), bound1.bound.getMaxY());
 
3019
                                points1[3] = EPoint.fromLambda(bound1.bound.getMaxX(), bound1.bound.getMinY());
 
3020
                                points1[4] = EPoint.fromLambda(bound1.bound.getMinX(), bound1.bound.getMinY());
 
3021
                        }
 
3022
 
 
3023
                        EPoint[] points2;
 
3024
                        if (bound2 instanceof SOGPoly)
 
3025
                        {
 
3026
                                SOGPoly p = (SOGPoly)bound2;
 
3027
                                Point[] po = p.poly.getPoints();
 
3028
                                points2 = new EPoint[po.length];
 
3029
                                for(int i=0; i<po.length; i++) points2[i] = EPoint.fromLambda(po[i].getX(), po[i].getY());
 
3030
                        } else
 
3031
                        {
 
3032
                                points2 = new EPoint[5];
 
3033
                                points2[0] = EPoint.fromLambda(bound2.bound.getMinX(), bound2.bound.getMinY());
 
3034
                                points2[1] = EPoint.fromLambda(bound2.bound.getMinX(), bound2.bound.getMaxY());
 
3035
                                points2[2] = EPoint.fromLambda(bound2.bound.getMaxX(), bound2.bound.getMaxY());
 
3036
                                points2[3] = EPoint.fromLambda(bound2.bound.getMaxX(), bound2.bound.getMinY());
 
3037
                                points2[4] = EPoint.fromLambda(bound2.bound.getMinX(), bound2.bound.getMinY());
 
3038
                        }
 
3039
 
 
3040
                        // now look for line intersections
 
3041
                        for(int i=1; i<points1.length; i++)
 
3042
                        {
 
3043
                                EPoint p1a = points1[i-1];
 
3044
                                EPoint p1b = points1[i];
 
3045
                                if (p1a.getX() == p1b.getX() && p1a.getY() == p1b.getY()) continue;
 
3046
                                double l1X = Math.min(p1a.getX(), p1b.getX());
 
3047
                                double h1X = Math.max(p1a.getX(), p1b.getX());
 
3048
                                double l1Y = Math.min(p1a.getY(), p1b.getY());
 
3049
                                double h1Y = Math.max(p1a.getY(), p1b.getY());
 
3050
                                for(int j=1; j<points2.length; j++)
 
3051
                                {
 
3052
                                        EPoint p2a = points2[j-1];
 
3053
                                        EPoint p2b = points2[j];
 
3054
                                        if (p2a.getX() == p2b.getX() && p2a.getY() == p2b.getY()) continue;
 
3055
                                        double l2X = Math.min(p2a.getX(), p2b.getX());
 
3056
                                        double h2X = Math.max(p2a.getX(), p2b.getX());
 
3057
                                        double l2Y = Math.min(p2a.getY(), p2b.getY());
 
3058
                                        double h2Y = Math.max(p2a.getY(), p2b.getY());
 
3059
 
 
3060
                                        if (l1X == h1X)
 
3061
                                        {
 
3062
                                                // line 1 is vertical
 
3063
                                                if (l2X == h2X)
 
3064
                                                {
 
3065
                                                        // both lines are vertical
 
3066
                                                        if (l1X != l2X) continue;
 
3067
                                                        if (h1Y > l2Y && h2Y > l1Y) return true;
 
3068
                                                        continue;
 
3069
                                                }
 
3070
 
 
3071
                                                // line one vertical, line two horizontal
 
3072
                                                if (l1X > l2X && l1X < h2X && l2Y > l1Y && l2Y < h1Y) return true;
 
3073
                                                continue;
 
3074
                                        } else
 
3075
                                        {
 
3076
                                                // line 1 is horizontal
 
3077
                                                if (l2Y == h2Y)
 
3078
                                                {
 
3079
                                                        // both lines are horizontal
 
3080
                                                        if (l1Y != l2Y) continue;
 
3081
                                                        if (h1X > l2X && h2X > l1X) return true;
 
3082
                                                        continue;
 
3083
                                                }
 
3084
 
 
3085
                                                // line one horizontal, line two vertical
 
3086
                                                if (l1Y > l2Y && l1Y < h2Y && l2X > l1X && l2X < h1X) return true;
 
3087
                                                continue;
 
3088
                                        }
 
3089
                                }
 
3090
                        }
 
3091
 
 
3092
                        // no intersection. Check for complete surround
 
3093
                        Poly p1 = new Poly(points1);
 
3094
                        if (p1.contains(points2[0])) return true;
 
3095
 
 
3096
                        Poly p2 = new Poly(points2);
 
3097
                        if (p2.contains(points1[0])) return true;
 
3098
 
 
3099
                        // they do not intersect
 
3100
                        return false;
1932
3101
                }
1933
3102
 
1934
3103
                /**
1936
3105
                 */
1937
3106
                private void addBlockagesAtPorts(PortInst pi)
1938
3107
                {
1939
 
                        MutableInteger netIDUse = new MutableInteger(netID.intValue() + OFFSETVIRTUAL);
 
3108
                        MutableInteger netIDUse = new MutableInteger(netID.intValue() + BLOCKAGEFAKEENDPOINT);
1940
3109
                        PolyBase poly = pi.getPoly();
1941
3110
                        Rectangle2D portBounds = poly.getBounds2D();
1942
3111
                        ArcProto[] poss = getPossibleConnections(pi.getPortProto());
1955
3124
                        if (lowMetal < 0) return;
1956
3125
 
1957
3126
                        // reserve space on layers above and below
 
3127
                        double x = pi.getCenter().getX(), y = pi.getCenter().getY();
1958
3128
                        Map<Layer,List<Rectangle2D>> blockageRects = new HashMap<Layer,List<Rectangle2D>>();
1959
3129
                        for (int via = lowMetal - 2; via < highMetal; via++)
1960
3130
                        {
1961
3131
                                if (via < 0 || via >= numMetalLayers - 1) continue;
1962
3132
                                List<MetalVia> mvs = metalVias[via].getVias();
 
3133
                                if (is2X(via, x, y, x, y) || (via+1 < numMetalLayers && is2X(via+1, x, y, x, y)))
 
3134
                                {
 
3135
                                        List<MetalVia> mvs2X = metalVias2X[via].getVias();
 
3136
                                        if (mvs2X.size() > 0) mvs = mvs2X;
 
3137
                                }
1963
3138
                                int upper = mvs.size();
1964
3139
//upper = 1;   // Used to be uncommented, then ends got blocked
1965
3140
                                for(int j=0; j<upper; j++)
1982
3157
                                                Rectangle2D bounds = new Rectangle2D.Double(metalBounds.getMinX() + portBounds.getCenterX(),
1983
3158
                                                        metalBounds.getMinY() + portBounds.getCenterY(), metalBounds.getWidth(), metalBounds.getHeight());
1984
3159
 
 
3160
                                                // if gridding is forced and this layer is not on grid, do not place blockage
 
3161
                                                int layNum = layer.getFunction().getLevel() - 1;
 
3162
                                                boolean hor = true;
 
3163
                                                if (sogp.isHorizontalEven())
 
3164
                                                {
 
3165
                                                        if ((layNum%2) == 0) hor = false;
 
3166
                                                } else
 
3167
                                                {
 
3168
                                                        if ((layNum%2) != 0) hor = false;
 
3169
                                                }
 
3170
                                                if (forceGridArcs[layNum])
 
3171
                                                {
 
3172
                                                        if (hor)
 
3173
                                                        {
 
3174
                                                                if (!isOnYGrid(layNum, bounds.getCenterY())) continue;
 
3175
                                                        } else
 
3176
                                                        {
 
3177
                                                                if (!isOnXGrid(layNum, bounds.getCenterX())) continue;
 
3178
                                                        }
 
3179
                                                }
 
3180
 
1985
3181
                                                // only add blockage if there is nothing else present
1986
 
                                                if (NEWBLOCKAGE)
1987
 
                                                {
1988
 
                                                        boolean free = true;
1989
 
                                                        BlockageTree bTree = rTrees.getMetalTree(layer);
1990
 
                                                        if (!bTree.isEmpty())
1991
 
                                                        {
1992
 
                                                                for (Iterator<SOGBound> sea = bTree.search(bounds); sea.hasNext();)
1993
 
                                                                {
1994
 
                                                                        SOGBound sBound = sea.next();
1995
 
                                                                        int netValue = 0;
1996
 
                                                                        if (sBound.getNetID() != null) netValue = sBound.getNetID().intValue();
1997
 
                                                                        if (netValue != netID.intValue()) continue;
1998
 
                                                                        if (sBound.getBounds().getMinX() > bounds.getMinX() ||
1999
 
                                                                                sBound.getBounds().getMaxX() < bounds.getMaxX() ||
2000
 
                                                                                sBound.getBounds().getMinY() > bounds.getMinY() ||
2001
 
                                                                                sBound.getBounds().getMaxY() < bounds.getMaxY()) continue;
2002
 
                                                                        free = false;
2003
 
                                                                        break;
2004
 
                                                                }
2005
 
                                                        }
2006
 
                                                        if (free)
2007
 
                                                        {
2008
 
                                                                List<Rectangle2D> rects = blockageRects.get(layer);
2009
 
                                                                if (rects == null) blockageRects.put(layer, rects = new ArrayList<Rectangle2D>());
2010
 
                                                                rects.add(bounds);
2011
 
                                                        }
2012
 
                                                } else
2013
 
                                                {
2014
 
                                                        // old blockage code
2015
 
                                                        boolean free = true;
2016
 
                                                        BlockageTree bTree = rTrees.getMetalTree(layer);
2017
 
                                                        if (!bTree.isEmpty())
2018
 
                                                        {
2019
 
                                                                for (Iterator<SOGBound> sea = bTree.search(bounds); sea.hasNext();)
2020
 
                                                                {
2021
 
                                                                        SOGBound sBound = sea.next();
2022
 
                                                                        if (sBound.getBounds().getMinX() > bounds.getMaxX() ||
2023
 
                                                                                sBound.getBounds().getMaxX() < bounds.getMinX() ||
2024
 
                                                                                sBound.getBounds().getMinY() > bounds.getMaxY() ||
2025
 
                                                                                sBound.getBounds().getMaxY() < bounds.getMinY()) continue;
2026
 
                                                                        if (sBound.isSameBasicNet(netIDUse)) continue;
2027
 
                                                                        free = false;
2028
 
                                                                        break;
2029
 
                                                                }
2030
 
                                                        }
2031
 
                                                        if (free) addRectangle(bounds, layer, netIDUse, false, false);
 
3182
                                                boolean free = true;
 
3183
                                                BlockageTree bTree = rTrees.getMetalTree(layer);
 
3184
                                                if (!bTree.isEmpty())
 
3185
                                                {
 
3186
                                                        for (Iterator<SOGBound> sea = bTree.search(bounds); sea.hasNext();)
 
3187
                                                        {
 
3188
                                                                SOGBound sBound = sea.next();
 
3189
                                                                int netValue = 0;
 
3190
                                                                if (sBound.getNetID() != null) netValue = sBound.getNetID().intValue();
 
3191
                                                                if (netValue != netID.intValue()) continue;
 
3192
                                                                if (sBound.getBounds().getMinX() > bounds.getMinX() ||
 
3193
                                                                        sBound.getBounds().getMaxX() < bounds.getMaxX() ||
 
3194
                                                                        sBound.getBounds().getMinY() > bounds.getMinY() ||
 
3195
                                                                        sBound.getBounds().getMaxY() < bounds.getMaxY()) continue;
 
3196
                                                                free = false;
 
3197
                                                                break;
 
3198
                                                        }
 
3199
                                                }
 
3200
                                                if (free)
 
3201
                                                {
 
3202
                                                        List<Rectangle2D> rects = blockageRects.get(layer);
 
3203
                                                        if (rects == null) blockageRects.put(layer, rects = new ArrayList<Rectangle2D>());
 
3204
                                                        rects.add(bounds);
2032
3205
                                                }
2033
3206
                                        }
2034
3207
                                }
2035
3208
                        }
2036
 
                        if (NEWBLOCKAGE)
 
3209
 
 
3210
                        for(Layer layer : blockageRects.keySet())
2037
3211
                        {
2038
 
                                for(Layer layer : blockageRects.keySet())
 
3212
                                List<Rectangle2D> rects = blockageRects.get(layer);
 
3213
                                for(int i=0; i<rects.size(); i++)
2039
3214
                                {
2040
 
                                        List<Rectangle2D> rects = blockageRects.get(layer);
2041
 
                                        for(int i=0; i<rects.size(); i++)
 
3215
                                        Rectangle2D bound1 = rects.get(i);
 
3216
                                        for(int j=0; j<rects.size(); j++)
2042
3217
                                        {
2043
 
                                                Rectangle2D bound1 = rects.get(i);
2044
 
                                                for(int j=0; j<rects.size(); j++)
 
3218
                                                if (j == i) continue;
 
3219
                                                Rectangle2D bound2 = rects.get(j);
 
3220
                                                if (bound1.getMinX() <= bound2.getMinX() && bound1.getMaxX() >= bound2.getMaxX() &&
 
3221
                                                        bound1.getMinY() <= bound2.getMinY() && bound1.getMaxY() >= bound2.getMaxY())
2045
3222
                                                {
2046
 
                                                        if (j == i) continue;
2047
 
                                                        Rectangle2D bound2 = rects.get(j);
2048
 
                                                        if (bound1.getMinX() <= bound2.getMinX() && bound1.getMaxX() >= bound2.getMaxX() &&
2049
 
                                                                bound1.getMinY() <= bound2.getMinY() && bound1.getMaxY() >= bound2.getMaxY())
2050
 
                                                        {
2051
 
                                                                // bound2 is smaller and can be eliminated
2052
 
                                                                rects.remove(j);
2053
 
                                                                if (i > j) i--;
2054
 
                                                                j--;
2055
 
                                                        }
 
3223
                                                        // bound2 is smaller and can be eliminated
 
3224
                                                        rects.remove(j);
 
3225
                                                        if (i > j) i--;
 
3226
                                                        j--;
2056
3227
                                                }
2057
3228
                                        }
2058
 
                                        for(Rectangle2D bounds : rects)
2059
 
                                        {
2060
 
                                                SOGBound rtn = addRectangle(bounds, layer, netIDUse, false, false);
2061
 
                                                if (endBlockages == null)
2062
 
                                                        endBlockages = new HashMap<Layer,List<SOGBound>>();
2063
 
                                                List<SOGBound> blocksOnLayer = endBlockages.get(layer);
2064
 
                                                if (blocksOnLayer == null) endBlockages.put(layer, blocksOnLayer = new ArrayList<SOGBound>());
2065
 
                                                blocksOnLayer.add(rtn);
2066
 
                                        }
 
3229
                                }
 
3230
                                for(Rectangle2D bounds : rects)
 
3231
                                {
 
3232
                                        SOGBound rtn = addRectangle(bounds, layer, netIDUse, false, false);
 
3233
                                        if (endBlockages == null)
 
3234
                                                endBlockages = new HashMap<Layer,List<SOGBound>>();
 
3235
                                        List<SOGBound> blocksOnLayer = endBlockages.get(layer);
 
3236
                                        if (blocksOnLayer == null) endBlockages.put(layer, blocksOnLayer = new ArrayList<SOGBound>());
 
3237
                                        blocksOnLayer.add(rtn);
2067
3238
                                }
2068
3239
                        }
2069
3240
                }
2083
3254
                        double surround[], double x, double y)
2084
3255
                {
2085
3256
                        // get the R-Tree data for the metal layer
2086
 
                        Layer layer = metalLayers[metNo];
2087
 
                        BlockageTree bTree = rTrees.getMetalTree(layer);
 
3257
                        BlockageTree bTree = rTrees.getMetalTree(primaryMetalLayer[metNo]);
2088
3258
                        bTree.lock();
2089
3259
                        try {
2090
3260
                                // compute the area to search
2103
3273
                                                DBMath.isGreaterThanOrEqualTo(bound.getMinY(), hY)) continue;
2104
3274
 
2105
3275
                                        // ignore if on the same net
2106
 
                                        if (sBound.isSameBasicNet(netID)) continue;
 
3276
                                        if (netID != null && sBound.isSameBasicNet(netID)) continue;
2107
3277
 
2108
3278
                                        // if this is a polygon, do closer examination
2109
3279
                                        if (sBound instanceof SOGPoly)
2129
3299
                 * @param y the Y coordinate at the center of the area to examine.
2130
3300
                 * @return a blocking SOGVia object that is in the area. Returns null if the area is clear.
2131
3301
                 */
2132
 
                public SOGVia getViaBlockage(MutableInteger netID, Layer layer, double halfWidth, double halfHeight, double x, double y)
 
3302
                public SOGVia getViaBlockage(MutableInteger netID, Layer layer, double surround, Rectangle2D rect)
 
3303
                {
 
3304
                        BlockageTree bTree = rTrees.getViaTree(layer);
 
3305
                        double rectLX = rect.getMinX(), rectHX = rect.getMaxX();
 
3306
                        double rectLY = rect.getMinY(), rectHY = rect.getMaxY();
 
3307
                        bTree.lock();
 
3308
                        try {
 
3309
                                if (bTree.isEmpty()) return null;
 
3310
 
 
3311
                                // see if there is anything in that area
 
3312
                                Rectangle2D searchArea = new Rectangle2D.Double(rect.getMinX()-surround-1, rect.getMinY()-surround-1,
 
3313
                                        rect.getWidth()+surround*2+2, rect.getHeight()+surround*2+2);
 
3314
                                for (Iterator<SOGBound> sea = bTree.search(searchArea); sea.hasNext();)
 
3315
                                {
 
3316
                                        SOGVia sLoc = (SOGVia)sea.next();
 
3317
                                        double testLX = sLoc.getBounds().getMinX(), testHX = sLoc.getBounds().getMaxX();
 
3318
                                        double testLY = sLoc.getBounds().getMinY(), testHY = sLoc.getBounds().getMaxY();
 
3319
                                        double dist = cutDistance(rectLX, rectHX, rectLY, rectHY, testLX, testHX, testLY, testHY);
 
3320
                                        if (DBMath.isGreaterThanOrEqualTo(dist, surround)) continue;
 
3321
                                        if (sLoc.isSameBasicNet(netID))
 
3322
                                        {
 
3323
                                                if (DBMath.areEquals(sLoc.getBounds().getCenterX(), rect.getCenterX()) && DBMath.areEquals(sLoc.getBounds().getCenterY(), rect.getCenterY())) continue;
 
3324
                                        }
 
3325
                                        return sLoc;
 
3326
                                }
 
3327
                                return null;
 
3328
                        } finally {
 
3329
                                bTree.unlock();
 
3330
                        }
 
3331
                }
 
3332
 
 
3333
                /**
 
3334
                 * Method to find a via blockage in the R-Tree.
 
3335
                 * @param netID the network ID of the desired space (vias at this point and on this netID are ignored).
 
3336
                 * @param layer the via layer being examined.
 
3337
                 * @param halfWidth half of the width of the area to examine.
 
3338
                 * @param halfHeight half of the height of the area to examine.
 
3339
                 * @param x the X coordinate at the center of the area to examine.
 
3340
                 * @param y the Y coordinate at the center of the area to examine.
 
3341
                 * @return a blocking SOGVia object that is in the area. Returns null if the area is clear.
 
3342
                 */
 
3343
                public SOGVia getViaBlockageOLD(MutableInteger netID, Layer layer, double halfWidth, double halfHeight, double x, double y)
2133
3344
                {
2134
3345
                        BlockageTree bTree = rTrees.getViaTree(layer);
2135
3346
                        bTree.lock();
2141
3352
                                for (Iterator<SOGBound> sea = bTree.search(searchArea); sea.hasNext();)
2142
3353
                                {
2143
3354
                                        SOGVia sLoc = (SOGVia)sea.next();
 
3355
                                        double distX = Math.abs(x - sLoc.getBounds().getCenterX()), distY = Math.abs(y - sLoc.getBounds().getCenterY());
 
3356
                                        if (DBMath.isGreaterThanOrEqualTo(distX, halfWidth) || DBMath.isGreaterThanOrEqualTo(distY, halfHeight)) continue;
2144
3357
                                        if (sLoc.isSameBasicNet(netID))
2145
3358
                                        {
2146
 
                                                if (DBMath.areEquals(sLoc.loc.getX(), x) && DBMath.areEquals(sLoc.loc.getY(), y)) continue;
 
3359
                                                if (DBMath.areEquals(sLoc.getBounds().getCenterX(), x) && DBMath.areEquals(sLoc.getBounds().getCenterY(), y)) continue;
2147
3360
                                        }
2148
3361
                                        return sLoc;
2149
3362
                                }
2190
3403
                                                }
2191
3404
                                                if (bestLoc != null)
2192
3405
                                                {
2193
 
                                                        SearchVertex svTap = new SearchVertex(bestLoc.getX(), bestLoc.getY(), result.wf.vertices.get(bestInsertPos).getZ(),
2194
 
                                                                0, null, null, 0, null);
 
3406
                                                        SearchVertex last = result.wf.vertices.get(bestInsertPos);
 
3407
                                                        SearchVertex svTap = new SearchVertex(bestLoc.getX(), bestLoc.getY(), last.getZ(), last.getC(),
 
3408
                                                                0, null, null, 0, null, 0);
2195
3409
                                                        result.wf.vertices.add(bestInsertPos, svTap);
2196
3410
                                                        spineTapMap.put(svTap, pi);
2197
3411
                                                }
2213
3427
                                        errorMessage = "Search for '" + routeName + "' aborted by user";
2214
3428
                                }
2215
3429
                                if (reroute) errorMessage = "(Retry) " + errorMessage;
2216
 
                                error(errorMessage);
 
3430
                                boolean isAnError = true;
 
3431
                                if (alreadyRouted)
 
3432
                                {
 
3433
                                        errorMessage += ", but route already exists in the circuit";
 
3434
                                        warn(errorMessage);
 
3435
                                        isAnError = false;
 
3436
                                } else
 
3437
                                {
 
3438
                                        error(errorMessage);
 
3439
                                }
2217
3440
                                if (result == svLimited || result == svExhausted)
2218
3441
                                {
2219
3442
                                        List<EPoint> lineList = new ArrayList<EPoint>();
2220
3443
                                        lineList.add(EPoint.fromLambda(aX, aY));
2221
3444
                                        lineList.add(EPoint.fromLambda(bX, bY));
2222
 
//                                      lineList.add(EPoint.fromLambda(routeBounds.getMinX(), routeBounds.getMinY()));
2223
 
//                                      lineList.add(EPoint.fromLambda(routeBounds.getMinX(), routeBounds.getMaxY()));
2224
 
//                                      lineList.add(EPoint.fromLambda(routeBounds.getMaxX(), routeBounds.getMaxY()));
2225
 
//                                      lineList.add(EPoint.fromLambda(routeBounds.getMaxX(), routeBounds.getMinY()));
2226
 
                                        errorLogger.logMessageWithLines(errorMessage, null, lineList, cell, 0, true);
 
3445
                                        loggedMessage = errorLogger.logMessageWithLines(errorMessage, null, lineList, cell, 0, isAnError);
2227
3446
                                }
2228
3447
                        }
2229
 
                        batch.completedRoute(this, result.wf);
 
3448
                        batch.completedRoute(this, result.wf, result);
2230
3449
                }
2231
3450
        }
2232
3451
 
2237
3456
                final List<RouteArc> arcsToRoute = new ArrayList<RouteArc>();
2238
3457
                final List<Integer> nodesIDsToKill = new ArrayList<Integer>();
2239
3458
                final List<Integer> arcsIDsToKill = new ArrayList<Integer>();
2240
 
                final List<RouteAddUnrouted> unroutedToAdd = new ArrayList<RouteAddUnrouted>();
 
3459
                final Map<RouteAddUnrouted,String> unroutedToAdd = new HashMap<RouteAddUnrouted,String>();
2241
3460
 
2242
3461
                public RouteResolution(CellId cellId)
2243
3462
                {
2252
3471
 
2253
3472
                public void killArc(ArcInst ai) { arcsIDsToKill.add(Integer.valueOf(ai.getArcId())); }
2254
3473
 
2255
 
                public void addUnrouted(PortInst piA, PortInst piB) { unroutedToAdd.add(new RouteAddUnrouted(piA, piB)); }
 
3474
                public void addUnrouted(PortInst piA, PortInst piB, String name) { unroutedToAdd.put(new RouteAddUnrouted(piA, piB), name); }
2256
3475
 
2257
3476
                public void clearRoutes()
2258
3477
                {
2321
3540
                        this.tapConnection = tapConnection;
2322
3541
                        this.nr = nr;
2323
3542
 
 
3543
                        if (np.getFunction() == PrimitiveNode.Function.PIN) return;
2324
3544
                        NodeInst ni = NodeInst.makeDummyInstance(np, soge.ep, loc, wid, hei, orient);
2325
3545
                        FixpTransform trans = ni.rotateOut();
2326
3546
                        Poly[] nodeInstPolyList = np.getTechnology().getShapeOfNode(ni, true, false, null);
2411
3631
                        // presuming a simple arc shape
2412
3632
                        EPoint fromLoc = from.loc;
2413
3633
                        EPoint toLoc = to.loc;
2414
 
                        totalWireLength += fromLoc.distance(toLoc);
 
3634
                        
2415
3635
                        Poly poly = null;
2416
3636
                        if (fromLoc.getX() == toLoc.getX())
2417
3637
                        {
2444
3664
                                        String layerName = "";
2445
3665
                                        if (layer != null) layerName = " " + layer.getName();
2446
3666
                                        System.out.println("WARNING: angled" + layerName + " wire from (" +
2447
 
                                                fromLoc.getX() + "," + fromLoc.getY() + ") to (" + toLoc.getX() + "," + toLoc.getY() + ")");
 
3667
                                                TextUtils.formatDistance(fromLoc.getX()) + "," + TextUtils.formatDistance(fromLoc.getY()) + ") to (" +
 
3668
                                                TextUtils.formatDistance(toLoc.getX()) + "," + TextUtils.formatDistance(toLoc.getY()) + ")");
2448
3669
                                }
2449
3670
                        }
2450
3671
                        if (poly != null && layer != null)
2495
3716
                /** Used search vertices while running wavefront (debug). */    private final List<SearchVertex> inactive;
2496
3717
                /** Resulting list of vertices found for this wavefront. */             List<SearchVertex> vertices;
2497
3718
                /** Set true to abort this wavefront's search. */                               volatile boolean abort;
 
3719
                /** true if debugging this wavefront */                                                 private boolean debuggingWavefront;
 
3720
                /** the final SearchVertex for this wavefront. */                               private SearchVertex solution;
2498
3721
                /** The starting and ending ports of the wavefront. */                  final PortInst from, to;
2499
3722
                /** The starting X/Y coordinates of the wavefront. */                   final double fromX, fromY;
2500
3723
                /** The starting area of the wavefront. */                                              final FixpRectangle fromRect;
2501
 
                /** The starting metal layer of the wavefront. */                               final int fromZ;
 
3724
                /** The starting metal layer of the wavefront. */                               final int fromZ, fromC;
2502
3725
                /** The ending X/Y coordinates of the wavefront. */                             final double toX, toY;
2503
3726
                /** The ending area of the wavefront. */                                                final FixpRectangle toRect;
2504
3727
                /** The expanded grid of the ending area of the wavefront. */   final FixpRectangle toRectGridded;
2505
 
                /** The ending metal layer of the wavefront. */                                 final int toZ;
 
3728
                /** The ending metal layer of the wavefront. */                                 final int toZ, toC;
 
3729
                /** The maximum taper lengths. */                                                               final double fromTaperLen, toTaperLen;
2506
3730
                /** Count of the number of wavefront advances made. */                  int numStepsMade;
2507
3731
                /** Global routing order for this wavefront direction. */               Rectangle2D [] orderedBuckets;
2508
3732
                /** Global routing lowest bucket for each step. */                              int [] orderedBase;
2509
 
                /** Network ID bits for ends of route. */                                               final int fromBit, toBit;
 
3733
                /** Network ID bits for ends of route. */                                               final int fromBit;
2510
3734
                /** Direction to move through global routing buckets */                 final int globalRoutingDelta;
2511
3735
                @SuppressWarnings({ "unchecked" } )
2512
3736
                /** Search vertices found while running the wavefront. */               final Map<Integer, Map<Integer,SearchVertex>>[] searchVertexPlanes = new Map[numMetalLayers];
2514
3738
                /** true when searching finished successfully or failed */      private boolean finished;
2515
3739
                /** array for optimized vertices (allocated once) */                    private List<SearchVertex> optimizedList = new ArrayList<SearchVertex>();
2516
3740
 
2517
 
                Wavefront(NeededRoute nr, PortInst from, FixpRectangle fromRect, double fromX, double fromY, int fromZ, int fromBit,
2518
 
                        PortInst to, FixpRectangle toRect, FixpRectangle toRectGridded, double toX, double toY, int toZ, int toBit, int globalRoutingDelta, String name)
 
3741
                Wavefront(NeededRoute nr,
 
3742
                        PortInst from, FixpRectangle fromRect, double fromX, double fromY, int fromZ, int fromC, double fromTaperLen, int fromBit,
 
3743
                        PortInst to, FixpRectangle toRect, FixpRectangle toRectGridded, double toX, double toY, int toZ, int toC, double toTaperLen,
 
3744
                        int globalRoutingDelta, String name, boolean debugIt)
2519
3745
                {
2520
3746
                        this.nr = nr;
2521
3747
                        this.from = from;
2522
3748
                        this.fromX = fromX;
2523
3749
                        this.fromY = fromY;
2524
3750
                        this.fromZ = fromZ;
 
3751
                        this.fromC = fromC;
2525
3752
                        this.fromRect = fromRect;
2526
3753
                        this.fromBit = fromBit;
2527
3754
                        this.to = to;
2528
3755
                        this.toX = toX;
2529
3756
                        this.toY = toY;
2530
3757
                        this.toZ = toZ;
 
3758
                        this.toC = toC;
2531
3759
                        this.toRect = toRect;
2532
3760
                        this.toRectGridded = toRectGridded;
2533
 
                        this.toBit = toBit;
 
3761
                        this.fromTaperLen = fromTaperLen;
 
3762
                        this.toTaperLen = toTaperLen;
2534
3763
                        if (nr.buckets == null) globalRoutingDelta = 0;
2535
3764
                        this.globalRoutingDelta = globalRoutingDelta;
2536
3765
                        this.name = name;
2539
3768
                        inactive = new ArrayList<SearchVertex>();
2540
3769
                        vertices = null;
2541
3770
                        abort = false;
 
3771
                        debuggingWavefront = debugIt;
2542
3772
 
2543
 
                        SearchVertex svStart = new SearchVertex(fromX, fromY, fromZ, 0, null, null, 0, this);
 
3773
                        SearchVertex svStart = new SearchVertex(fromX, fromY, fromZ, fromC, 0, null, null, 0, this, 0);
 
3774
                        if (debuggingWavefront) RoutingDebug.ensureDebuggingShadow(svStart, true);
2544
3775
                        if (globalRoutingDelta != 0)
2545
3776
                        {
2546
3777
                                orderedBuckets = new Rectangle2D[nr.buckets.length];
2621
3852
 
2622
3853
                public int getFromZ() { return fromZ; }
2623
3854
 
 
3855
                public int getFromMask() { return fromC; }
 
3856
 
2624
3857
                public double getToX() { return toX; }
2625
3858
 
2626
3859
                public double getToY() { return toY; }
2627
3860
 
2628
3861
                public int getToZ() { return toZ; }
2629
3862
 
 
3863
                public int getToMask() { return toC; }
 
3864
 
2630
3865
                public Set<SearchVertex> getActive() { return active.getSet(); }
2631
3866
 
2632
3867
                public List<SearchVertex> getInactive() { return inactive; }
2637
3872
 
2638
3873
                public Rectangle2D[] getOrderedBuckets() { return orderedBuckets; }
2639
3874
 
 
3875
                public SearchVertex getFinalSearchVertex() { return solution; }
 
3876
 
2640
3877
                public SearchVertex getNextSearchVertex()
2641
3878
                {
2642
3879
                        SearchVertex sv = active.getFirst();
2671
3908
                {
2672
3909
                        Map<Integer, Map<Integer,SearchVertex>> plane = searchVertexPlanes[z];
2673
3910
                        if (plane == null)
2674
 
                                searchVertexPlanes[z] = plane = new HashMap<Integer, Map<Integer,SearchVertex>>();
 
3911
                                searchVertexPlanes[z] = plane = new TreeMap<Integer, Map<Integer,SearchVertex>>();
2675
3912
                        Integer iY = new Integer((int)Math.round(y * DBMath.GRID));
2676
3913
                        Map<Integer,SearchVertex> row = plane.get(iY);
2677
3914
                        if (row == null)
2678
 
                                plane.put(iY, row = new HashMap<Integer,SearchVertex>());
 
3915
                                plane.put(iY, row = new TreeMap<Integer,SearchVertex>());
2679
3916
                        row.put(new Integer((int)Math.round(x * DBMath.GRID)), sv);
2680
3917
                }
2681
3918
 
2719
3956
                {
2720
3957
                        // stop if too many steps have been made
2721
3958
                        numStepsMade++;
2722
 
                        if (numStepsMade > nr.complexityLimit) return svLimited;
 
3959
                        if (numStepsMade > nr.complexityLimit) return solution = svLimited;
2723
3960
 
2724
3961
                        // get the lowest cost point
2725
3962
                        SearchVertex svCurrent = getNextSearchVertex();
2726
 
                        if (svCurrent == svExhausted) return svCurrent;
 
3963
                        if (svCurrent == svExhausted) return solution = svCurrent;
2727
3964
                        active.remove(svCurrent);
2728
3965
                        inactive.add(svCurrent);
2729
3966
 
2730
3967
                        double curX = svCurrent.getX();
2731
3968
                        double curY = svCurrent.getY();
2732
3969
                        int curZ = svCurrent.getZ();
 
3970
                        int curC = svCurrent.getC();
2733
3971
 
2734
 
                        if (RoutingDebug.isActive())
 
3972
                        if (debuggingWavefront)
2735
3973
                        {
2736
3974
                                initDebugStrings();
2737
 
                                String str = "At: (" + TextUtils.formatDouble(curX) + "," + TextUtils.formatDouble(curY) +
2738
 
                                        ",M" + (curZ + 1) + "), Cost: " + svCurrent.cost;
 
3975
                                String str = "At: (" + TextUtils.formatDistance(curX) + "," + TextUtils.formatDistance(curY) +
 
3976
                                        "," + describeMetal(curZ,curC) + "), Cost: " + svCurrent.cost;
2739
3977
                                if (globalRoutingDelta == 0) str += ", NO Global Routing"; else
2740
3978
                                        str += ", Global Routing Bucket: " + svCurrent.globalRoutingBucket;
2741
3979
                                setDebugStringHeader(str);
2744
3982
                        // see if automatic generation is requested
2745
3983
                        int lastDirection = svCurrent.getAutoGen();
2746
3984
                        if (lastDirection >= 0)
2747
 
                                svCurrent.generateIntermediateVertex(nr, lastDirection, toRectGridded);
 
3985
                                svCurrent.generateIntermediateVertex(lastDirection, toRectGridded, cell);
2748
3986
 
2749
3987
                        // look at all directions from this point
2750
3988
                        SearchVertex destinationSV = null;
2753
3991
                                // compute a neighboring point
2754
3992
                                double dx = 0, dy = 0;
2755
3993
                                int dz = 0;
2756
 
                                MutableBoolean foundDestination = null;
2757
 
                                boolean stuck = false;
 
3994
                                boolean tooFarFromEnd = false, closeToEnd = false;
 
3995
                                StringBuffer jumpExplanation = null;
 
3996
                                if (debuggingWavefront) jumpExplanation = new StringBuffer();
2758
3997
                                switch (i)
2759
3998
                                {
2760
3999
                                        case 0:                                 // move -X
2761
4000
                                                if (sogp.isForceHorVer() && ((curZ % 2) == 0) == sogp.isHorizontalEven())
2762
4001
                                                {
2763
 
                                                        if (RoutingDebug.isActive()) setDebugString(i, "Cannot move in this axis");
 
4002
                                                        if (debuggingWavefront) setDebugString(i, "Cannot move in -X axis");
2764
4003
                                                        continue;
2765
4004
                                                }
 
4005
                                                if (DBMath.areEquals(curY, toY) && toRectGridded.getMinX() < toRectGridded.getMaxX() &&
 
4006
                                                        curX >= toRectGridded.getMinX() && curX <= toRectGridded.getMaxX()) dx = toX - curX; else
2766
4007
                                                if (inDestGrid(toRectGridded, curX-GRAINSIZE, curY)) dx = -GRAINSIZE; else
2767
 
                                                        dx = nr.getLowerXGrid(curZ, curX-GRAINSIZE) - curX;
2768
 
 
2769
 
                                                double intermediate = nr.upToGrainAlways(curX + dx);
2770
 
                                                if (intermediate != curX + dx) dx = intermediate - curX;
2771
 
 
2772
 
                                                if (toX - curX < 0)
 
4008
                                                        dx = nr.getLowerXGrid(curZ, curX-GRAINSIZE).getCoordinate() - curX;
 
4009
 
 
4010
                                                if (nr.gridLocationsX[curZ] == null || !nr.forceGridArcs[curZ])
 
4011
                                                {
 
4012
                                                        double intermediate = nr.upToGrainAlways(curX + dx);
 
4013
                                                        if (intermediate != curX + dx) dx = intermediate - curX;
 
4014
                                                }
 
4015
 
 
4016
                                                if (toX < curX)
2773
4017
                                                {
2774
4018
                                                        // jump as far as possible toward goal
2775
 
                                                        if (ANYPOINTONDESTINATION) foundDestination = new MutableBoolean(false);
2776
 
                                                        dx = getJumpSize(svCurrent, curX, curY, curZ, dx, dy, foundDestination);
2777
 
                                                        if (dx >= 0) { dx = -1;  stuck = true; }
 
4019
                                                        dx = getJumpSize(svCurrent, curX, curY, curZ, dx, dy, jumpExplanation);
 
4020
                                                        if (dx >= 0) dx = -1;
 
4021
                                                }
 
4022
                                                if (nr.gridLocationsX[curZ] != null && nr.forceGridArcs[curZ] && (curX+dx != toX || curY != toY || curZ != toZ))
 
4023
                                                {
 
4024
                                                        double gridX = nr.getClosestXGrid(curZ, curX+dx).getCoordinate();
 
4025
                                                        if (gridX == curX)
 
4026
                                                        {
 
4027
                                                                if (debuggingWavefront)
 
4028
                                                                {
 
4029
                                                                        if (jumpExplanation.length() != 0) setDebugString(i, "Blocked by " + jumpExplanation.toString()); else
 
4030
                                                                        {
 
4031
                                                                                setDebugString(i, "Can only move to " + TextUtils.formatDistance(curX+dx) +
 
4032
                                                                                        " which is gridded right to " + TextUtils.formatDistance(gridX) + " (no movement)");
 
4033
                                                                        }
 
4034
                                                                }
 
4035
                                                                continue;
 
4036
                                                        }
 
4037
                                                        dx = gridX - curX;
2778
4038
                                                }
2779
4039
                                                break;
2780
4040
                                        case 1:                                 // move +X
2781
4041
                                                if (sogp.isForceHorVer() && ((curZ % 2) == 0) == sogp.isHorizontalEven())
2782
4042
                                                {
2783
 
                                                        if (RoutingDebug.isActive()) setDebugString(i, "Cannot move in this axis");
 
4043
                                                        if (debuggingWavefront) setDebugString(i, "Cannot move in +X axis");
2784
4044
                                                        continue;
2785
4045
                                                }
 
4046
                                                if (DBMath.areEquals(curY, toY) && toRectGridded.getMinX() < toRectGridded.getMaxX() &&
 
4047
                                                        curX >= toRectGridded.getMinX() && curX <= toRectGridded.getMaxX()) dx = toX - curX; else
2786
4048
                                                if (inDestGrid(toRectGridded, curX+GRAINSIZE, curY)) dx = GRAINSIZE; else
2787
 
                                                        dx = nr.getUpperXGrid(curZ, curX+GRAINSIZE) - curX;
2788
 
 
2789
 
                                                intermediate = nr.downToGrainAlways(curX + dx);
2790
 
                                                if (intermediate != curX + dx) dx = intermediate - curX;
2791
 
 
2792
 
                                                if (toX - curX > 0)
 
4049
                                                        dx = nr.getUpperXGrid(curZ, curX+GRAINSIZE).getCoordinate() - curX;
 
4050
 
 
4051
                                                if (nr.gridLocationsX[curZ] == null || !nr.forceGridArcs[curZ])
 
4052
                                                {
 
4053
                                                        double intermediate = nr.downToGrainAlways(curX + dx);
 
4054
                                                        if (intermediate != curX + dx) dx = intermediate - curX;
 
4055
                                                }
 
4056
 
 
4057
                                                if (toX > curX)
2793
4058
                                                {
2794
4059
                                                        // jump as far as possible toward goal
2795
 
                                                        if (ANYPOINTONDESTINATION) foundDestination = new MutableBoolean(false);
2796
 
                                                        dx = getJumpSize(svCurrent, curX, curY, curZ, dx, dy, foundDestination);
2797
 
                                                        if (dx <= 0) { dx = 1;  stuck = true; }
 
4060
                                                        dx = getJumpSize(svCurrent, curX, curY, curZ, dx, dy, jumpExplanation);
 
4061
                                                        if (dx <= 0) dx = 1;
 
4062
                                                }
 
4063
                                                if (nr.gridLocationsX[curZ] != null && nr.forceGridArcs[curZ] && (curX+dx != toX || curY != toY || curZ != toZ))
 
4064
                                                {
 
4065
                                                        double gridX = nr.getClosestXGrid(curZ, curX+dx).getCoordinate();
 
4066
                                                        if (gridX == curX)
 
4067
                                                        {
 
4068
                                                                if (debuggingWavefront)
 
4069
                                                                {
 
4070
                                                                        if (jumpExplanation.length() != 0) setDebugString(i, "Blocked by " + jumpExplanation.toString()); else
 
4071
                                                                        {
 
4072
                                                                                setDebugString(i, "Can only move to " + TextUtils.formatDistance(curX+dx) +
 
4073
                                                                                        " which is gridded left to " + TextUtils.formatDistance(gridX) + " (no movement)");
 
4074
                                                                        }
 
4075
                                                                }
 
4076
                                                                continue;
 
4077
                                                        }
 
4078
                                                        dx = gridX - curX;
2798
4079
                                                }
2799
4080
                                                break;
2800
4081
                                        case 2:                                 // move -Y
2801
4082
                                                if (sogp.isForceHorVer() && ((curZ % 2) != 0) == sogp.isHorizontalEven())
2802
4083
                                                {
2803
 
                                                        if (RoutingDebug.isActive()) setDebugString(i, "Cannot move in this axis");
 
4084
                                                        if (debuggingWavefront) setDebugString(i, "Cannot move in -Y axis");
2804
4085
                                                        continue;
2805
4086
                                                }
 
4087
                                                if (DBMath.areEquals(curX, toX) && toRectGridded.getMinY() < toRectGridded.getMaxY() &&
 
4088
                                                        curY >= toRectGridded.getMinY() && curY <= toRectGridded.getMaxY()) dy = toY - curY; else
2806
4089
                                                if (inDestGrid(toRectGridded, curX, curY-GRAINSIZE)) dy = -GRAINSIZE; else
2807
 
                                                        dy = nr.getLowerYGrid(curZ, curY-GRAINSIZE) - curY;
2808
 
 
2809
 
                                                intermediate = nr.upToGrainAlways(curY + dy);
2810
 
                                                if (intermediate != curY + dy) dy = intermediate - curY;
2811
 
 
2812
 
                                                if (toY - curY < 0)
 
4090
                                                        dy = nr.getLowerYGrid(curZ, curY-GRAINSIZE).getCoordinate() - curY;
 
4091
 
 
4092
                                                if (nr.gridLocationsY[curZ] == null || !nr.forceGridArcs[curZ])
 
4093
                                                {
 
4094
                                                        double intermediate = nr.upToGrainAlways(curY + dy);
 
4095
                                                        if (intermediate != curY + dy) dy = intermediate - curY;
 
4096
                                                }
 
4097
 
 
4098
                                                if (toY < curY)
2813
4099
                                                {
2814
4100
                                                        // jump as far as possible toward goal
2815
 
                                                        if (ANYPOINTONDESTINATION) foundDestination = new MutableBoolean(false);
2816
 
                                                        dy = getJumpSize(svCurrent, curX, curY, curZ, dx, dy, foundDestination);
2817
 
                                                        if (dy >= 0) { dy = -1;  stuck = true; }
 
4101
                                                        dy = getJumpSize(svCurrent, curX, curY, curZ, dx, dy, jumpExplanation);
 
4102
                                                        if (dy >= 0) dy = -1;
 
4103
                                                }
 
4104
                                                if (nr.gridLocationsY[curZ] != null && nr.forceGridArcs[curZ] && (curX != toX || curY+dy != toY || curZ != toZ))
 
4105
                                                {
 
4106
                                                        double gridY = nr.getClosestYGrid(curZ, curY+dy).getCoordinate();
 
4107
                                                        if (gridY == curY)
 
4108
                                                        {
 
4109
                                                                if (debuggingWavefront)
 
4110
                                                                {
 
4111
                                                                        if (jumpExplanation.length() != 0) setDebugString(i, "Blocked by " + jumpExplanation.toString()); else
 
4112
                                                                        {
 
4113
                                                                                setDebugString(i, "Can only move to " + TextUtils.formatDistance(curY+dy) +
 
4114
                                                                                        " which is gridded up to " + TextUtils.formatDistance(gridY) + " (no movement)");
 
4115
                                                                        }
 
4116
                                                                }
 
4117
                                                                continue;
 
4118
                                                        }
 
4119
                                                        dy = gridY - curY;
2818
4120
                                                }
2819
4121
                                                break;
2820
4122
                                        case 3:                                 // move +Y
2821
4123
                                                if (sogp.isForceHorVer() && ((curZ % 2) != 0) == sogp.isHorizontalEven())
2822
4124
                                                {
2823
 
                                                        if (RoutingDebug.isActive()) setDebugString(i, "Cannot move in this axis");
 
4125
                                                        if (debuggingWavefront) setDebugString(i, "Cannot move in +Y axis");
2824
4126
                                                        continue;
2825
4127
                                                }
 
4128
                                                if (DBMath.areEquals(curX, toX) && toRectGridded.getMinY() < toRectGridded.getMaxY() &&
 
4129
                                                        curY >= toRectGridded.getMinY() && curY <= toRectGridded.getMaxY()) dy = toY - curY; else
2826
4130
                                                if (inDestGrid(toRectGridded, curX, curY+GRAINSIZE)) dy = GRAINSIZE; else
2827
 
                                                        dy = nr.getUpperYGrid(curZ, curY+GRAINSIZE) - curY;
2828
 
 
2829
 
                                                intermediate = nr.downToGrainAlways(curY + dy);
2830
 
                                                if (intermediate != curY + dy) dy = intermediate - curY;
2831
 
 
2832
 
                                                if (toY - curY > 0)
 
4131
                                                        dy = nr.getUpperYGrid(curZ, curY+GRAINSIZE).getCoordinate() - curY;
 
4132
 
 
4133
                                                if (nr.gridLocationsY[curZ] == null || !nr.forceGridArcs[curZ])
 
4134
                                                {
 
4135
                                                        double intermediate = nr.downToGrainAlways(curY + dy);
 
4136
                                                        if (intermediate != curY + dy) dy = intermediate - curY;
 
4137
                                                }
 
4138
 
 
4139
                                                if (toY > curY)
2833
4140
                                                {
2834
4141
                                                        // jump as far as possible toward goal
2835
 
                                                        if (ANYPOINTONDESTINATION) foundDestination = new MutableBoolean(false);
2836
 
                                                        dy = getJumpSize(svCurrent, curX, curY, curZ, dx, dy, foundDestination);
2837
 
                                                        if (dy <= 0) { dy = 1;  stuck = true; }
 
4142
                                                        dy = getJumpSize(svCurrent, curX, curY, curZ, dx, dy, jumpExplanation);
 
4143
                                                        if (dy <= 0) dy = 1;
 
4144
                                                }
 
4145
                                                if (nr.gridLocationsY[curZ] != null && nr.forceGridArcs[curZ] && (curX != toX || curY+dy != toY || curZ != toZ))
 
4146
                                                {
 
4147
                                                        double gridY = nr.getClosestYGrid(curZ, curY+dy).getCoordinate();
 
4148
                                                        if (gridY == curY)
 
4149
                                                        {
 
4150
                                                                if (debuggingWavefront)
 
4151
                                                                {
 
4152
                                                                        if (jumpExplanation.length() != 0) setDebugString(i, "Blocked by " + jumpExplanation.toString()); else
 
4153
                                                                        {
 
4154
                                                                                setDebugString(i, "Can only move to " + TextUtils.formatDistance(curY+dy) +
 
4155
                                                                                        " which is gridded down to " + TextUtils.formatDistance(gridY) + " (no movement)");
 
4156
                                                                        }
 
4157
                                                                }
 
4158
                                                                continue;
 
4159
                                                        }
 
4160
                                                        dy = gridY - curY;
2838
4161
                                                }
2839
4162
                                                break;
2840
4163
                                        case 4:                                 // move -Z
2845
4168
                                                break;
2846
4169
                                }
2847
4170
 
2848
 
                                if (RoutingDebug.isActive())
 
4171
                                if (debuggingWavefront)
2849
4172
                                {
2850
4173
                                        switch (i)
2851
4174
                                        {
2852
 
                                                case 0: setDebugString(i, "Move -" + TextUtils.formatDouble(Math.abs(dx)));  break;
2853
 
                                                case 1: setDebugString(i, "Move +" + TextUtils.formatDouble(dx));            break;
2854
 
                                                case 2: setDebugString(i, "Move -" + TextUtils.formatDouble(Math.abs(dy)));  break;
2855
 
                                                case 3: setDebugString(i, "Move +" + TextUtils.formatDouble(dy));            break;
2856
 
                                                case 4: setDebugString(i, "Move -1");                                        break;
2857
 
                                                case 5: setDebugString(i, "Move +1");                                        break;
 
4175
                                                case 0:   case 1:
 
4176
                                                        setDebugString(i, "Move " + (dx < 0 ? "" : "+") + TextUtils.formatDistance(dx));
 
4177
                                                        break;
 
4178
                                                case 2:   case 3:
 
4179
                                                        setDebugString(i, "Move " + (dy < 0 ? "" : "+") + TextUtils.formatDistance(dy));
 
4180
                                                        break;
 
4181
                                                case 4: setDebugString(i, "Move -1");   break;
 
4182
                                                case 5: setDebugString(i, "Move +1");   break;
2858
4183
                                        }
2859
4184
                                }
2860
 
                                if (stuck && STICKTOJUMPEDGES)
2861
 
                                {
2862
 
                                        if (RoutingDebug.isActive()) completeDebugString(i, ": Cannot Move");
2863
 
                                        continue;
2864
 
                                }
2865
4185
 
2866
4186
                                // create the "next" step location
2867
4187
                                double nX = curX + dx;
2868
4188
                                double nY = curY + dy;
2869
4189
                                int nZ = curZ + dz;
 
4190
                                int nC = curC;
 
4191
                                if (dz == 0)
 
4192
                                {
 
4193
                                        // limit distance if running a taper on the initial segment
 
4194
                                        if (fromTaperLen >= 0 && !svCurrent.isOffInitialSegment())
 
4195
                                        {
 
4196
                                                // compute distance from start
 
4197
                                                double distX = nX - fromX;
 
4198
                                                double distY = nY - fromY;
 
4199
                                                double dist = Math.sqrt(distX*distX + distY*distY);
 
4200
                                                if (dist > fromTaperLen)
 
4201
                                                {
 
4202
                                                        if (debuggingWavefront) completeDebugString(i, ": initial taper is " + TextUtils.formatDistance(dist)
 
4203
                                                                + " from start but maximum taper is " + TextUtils.formatDistance(fromTaperLen));
 
4204
                                                        continue;
 
4205
                                                }
 
4206
                                        }
 
4207
                                        if (jumpExplanation != null && jumpExplanation.length() != 0)
 
4208
                                                completeDebugString(i, " [Stopped by " + jumpExplanation.toString() + "]");
 
4209
                                } else
 
4210
                                {
 
4211
                                        if (nZ < 0 || nZ >= numMetalLayers)
 
4212
                                        {
 
4213
                                                if (debuggingWavefront) completeDebugString(i, ": Out Of Bounds");
 
4214
                                                continue;
 
4215
                                        }
 
4216
                                        if (nr.preventArc(nZ))
 
4217
                                        {
 
4218
                                                if (debuggingWavefront) completeDebugString(i, ": Disallowed Arc");
 
4219
                                                continue;
 
4220
                                        }
 
4221
 
 
4222
                                        // if switching to destination layer that tapers but is too far away, mark that this cannot finish the route
 
4223
                                        if (nZ == toZ && toTaperLen >= 0 && (DBMath.areEquals(nX, toX) || DBMath.areEquals(nY, toY)))
 
4224
                                        {
 
4225
                                                // compute distance from end
 
4226
                                                double closest = Math.max(Math.abs(nX - toX),  Math.abs(nY - toY));
 
4227
                                                if (closest > toTaperLen)
 
4228
                                                {
 
4229
                                                        if (taperOnlyArcs[nZ])
 
4230
                                                        {
 
4231
                                                                if (debuggingWavefront) completeDebugString(i, ": Taper-only layer too far from destination");
 
4232
                                                                continue;
 
4233
                                                        }
 
4234
                                                        tooFarFromEnd = true;
 
4235
                                                } else
 
4236
                                                {
 
4237
                                                        closeToEnd = true;
 
4238
                                                }
 
4239
                                        }
 
4240
 
 
4241
                                        // if new layer has multiple masks, choose the color
 
4242
                                        if (metalLayers[nZ].length == 1) nC = 0; else
 
4243
                                        {
 
4244
                                                if (sogp.isForceHorVer())
 
4245
                                                {
 
4246
                                                        // layers are forced into tracks: get mask number from coordinate information
 
4247
                                                        if (((nZ % 2) == 0) == sogp.isHorizontalEven())
 
4248
                                                        {
 
4249
                                                                // new layer runs vertically
 
4250
                                                                if (nr.gridLocationsX[nZ] == null) System.out.println("WARNING: No X grid information for Metal " + (nZ+1)); else
 
4251
                                                                {
 
4252
                                                                        SeaOfGatesTrack sogt = nr.getClosestXGrid(nZ, nX);
 
4253
                                                                        nC = sogt.getMaskNum();
 
4254
                                                                        if (nC != 0)
 
4255
                                                                        {
 
4256
                                                                                if (nr.is2X(nZ, curX, curY, nX, nY)) nC = metalLayers[nZ].length + 1 - nC;
 
4257
                                                                        } else
 
4258
                                                                        {
 
4259
                                                                                System.out.println("WARNING: No mask color for Metal " + (nZ+1) + " at X=" + TextUtils.formatDistance(nX));
 
4260
                                                                        }
 
4261
                                                                }
 
4262
                                                        } else
 
4263
                                                        {
 
4264
                                                                // new layer runs horizontally
 
4265
                                                                if (nr.gridLocationsY[nZ] == null) System.out.println("WARNING: No Y grid information for Metal " + (nZ+1)); else
 
4266
                                                                {
 
4267
                                                                        SeaOfGatesTrack sogt = nr.getClosestYGrid(nZ, nY);
 
4268
                                                                        nC = sogt.getMaskNum();
 
4269
                                                                        if (nC != 0)
 
4270
                                                                        {
 
4271
                                                                                if (nr.is2X(nZ, curX, curY, nX, nY)) nC = metalLayers[nZ].length + 1 - nC;
 
4272
                                                                        } else
 
4273
                                                                        {
 
4274
                                                                                System.out.println("WARNING: No mask color for Metal " + (nZ+1) + " at Y=" + TextUtils.formatDistance(nY));
 
4275
                                                                        }
 
4276
                                                                }
 
4277
                                                        }
 
4278
                                                }
 
4279
 
 
4280
                                                if (nC == 0)
 
4281
                                                {
 
4282
                                                        // track rules failed, figure out color from general rules
 
4283
 
 
4284
                                                        // Rule 1: presume the same mask color as the previous metal
 
4285
                                                        nC = curC;
 
4286
 
 
4287
                                                        // Rule 2: if switching to destination layer, presume mask color of destination
 
4288
                                                        if (nZ == toZ) nC = toC;
 
4289
 
 
4290
                                                        // Rule 3: if over new layer, make sure to match its mask color
 
4291
                                                        if (tech.hasColoredMetalLayer(primaryMetalLayer[nZ]))
 
4292
                                                        {
 
4293
                                                                BlockageTree bTree = rTrees.getMetalTree(primaryMetalLayer[nZ]);
 
4294
                                                                bTree.lock();
 
4295
                                                                try {
 
4296
                                                                        if (!bTree.isEmpty())
 
4297
                                                                        {
 
4298
                                                                                // see if there is anything under this point
 
4299
                                                                                Rectangle2D searchArea = new Rectangle2D.Double(nX, nY, 0, 0);
 
4300
                                                                                for (Iterator<SOGBound> sea = bTree.search(searchArea); sea.hasNext(); )
 
4301
                                                                                {
 
4302
                                                                                        SOGBound sBound = sea.next();
 
4303
                                                                                        if (sBound.isSameBasicNet(nr.netID))
 
4304
                                                                                                nC = sBound.maskLayer;
 
4305
                                                                                }
 
4306
                                                                        }
 
4307
                                                                } finally {
 
4308
                                                                        bTree.unlock();
 
4309
                                                                }
 
4310
                                                        }
 
4311
                                                }
 
4312
                                        }
 
4313
                                }
2870
4314
 
2871
4315
                                // force next step to be inside of global routing area
2872
 
                                if (foundDestination != null && !foundDestination.booleanValue()) foundDestination = null;
2873
 
                                if (globalRoutingDelta != 0 && foundDestination == null)
 
4316
                                if (globalRoutingDelta != 0)
2874
4317
                                {
2875
4318
                                        Rectangle2D limit = orderedBuckets[svCurrent.globalRoutingBucket];
2876
4319
                                        if (nX < limit.getMinX())
2877
4320
                                        {
2878
4321
                                                nX = limit.getMinX();
2879
 
                                                if (!inDestGrid(toRectGridded, nX, curY)) nX = nr.getUpperXGrid(curZ, nX);
 
4322
                                                if (!inDestGrid(toRectGridded, nX, curY)) nX = nr.getUpperXGrid(curZ, nX).getCoordinate();
2880
4323
                                                dx = nX - curX;
2881
4324
                                                if (dx == 0)
2882
4325
                                                {
2883
 
                                                        if (RoutingDebug.isActive()) completeDebugString(i, ": Out Of Global Routing X Bounds");
 
4326
                                                        if (debuggingWavefront) completeDebugString(i, ": Out Of Global Routing X Bounds");
2884
4327
                                                        continue;
2885
4328
                                                }
2886
4329
                                        }
2887
4330
                                        if (nX > limit.getMaxX())
2888
4331
                                        {
2889
4332
                                                nX = limit.getMaxX();
2890
 
                                                if (!inDestGrid(toRectGridded, nX, curY)) nX = nr.getLowerXGrid(curZ, nX);
 
4333
                                                if (!inDestGrid(toRectGridded, nX, curY)) nX = nr.getLowerXGrid(curZ, nX).getCoordinate();
2891
4334
                                                dx = nX - curX;
2892
4335
                                                if (dx == 0)
2893
4336
                                                {
2894
 
                                                        if (RoutingDebug.isActive()) completeDebugString(i, ": Out Of Global Routing X Bounds");
 
4337
                                                        if (debuggingWavefront) completeDebugString(i, ": Out Of Global Routing X Bounds");
2895
4338
                                                        continue;
2896
4339
                                                }
2897
4340
                                        }
2898
4341
                                        if (nY < limit.getMinY())
2899
4342
                                        {
2900
4343
                                                nY = limit.getMinY();
2901
 
                                                if (!inDestGrid(toRectGridded, curX, nY)) nY = nr.getUpperYGrid(curZ, nY);
 
4344
                                                if (!inDestGrid(toRectGridded, curX, nY)) nY = nr.getUpperYGrid(curZ, nY).getCoordinate();
2902
4345
                                                dy = nY - curY;
2903
4346
                                                if (dy == 0)
2904
4347
                                                {
2905
 
                                                        if (RoutingDebug.isActive()) completeDebugString(i, ": Out Of Global Routing Y Bounds");
 
4348
                                                        if (debuggingWavefront) completeDebugString(i, ": Out Of Global Routing Y Bounds");
2906
4349
                                                        continue;
2907
4350
                                                }
2908
4351
                                        }
2909
4352
                                        if (nY > limit.getMaxY())
2910
4353
                                        {
2911
4354
                                                nY = limit.getMaxY();
2912
 
                                                if (!inDestGrid(toRectGridded, curX,nY)) nY = nr.getLowerYGrid(curZ, nY);
 
4355
                                                if (!inDestGrid(toRectGridded, curX,nY)) nY = nr.getLowerYGrid(curZ, nY).getCoordinate();
2913
4356
                                                dy = nY - curY;
2914
4357
                                                if (dy == 0)
2915
4358
                                                {
2916
 
                                                        if (RoutingDebug.isActive()) completeDebugString(i, ": Out Of Global Routing Y Bounds");
 
4359
                                                        if (debuggingWavefront) completeDebugString(i, ": Out Of Global Routing Y Bounds");
2917
4360
                                                        continue;
2918
4361
                                                }
2919
4362
                                        }
2923
4366
                                if (nX < nr.routeBounds.getMinX())
2924
4367
                                {
2925
4368
                                        nX = nr.routeBounds.getMinX();
2926
 
                                        if (!inDestGrid(toRectGridded, nX, curY)) nX = nr.getUpperXGrid(curZ, nX);
 
4369
                                        if (!inDestGrid(toRectGridded, nX, curY)) nX = nr.getUpperXGrid(curZ, nX).getCoordinate();
2927
4370
                                        dx = nX - curX;
2928
4371
                                        if (dx == 0)
2929
4372
                                        {
2930
 
                                                if (RoutingDebug.isActive()) completeDebugString(i, ": Out Of X Bounds");
 
4373
                                                if (debuggingWavefront) completeDebugString(i, ": Out Of X Bounds");
2931
4374
                                                continue;
2932
4375
                                        }
2933
4376
                                }
2934
4377
                                if (nX > nr.routeBounds.getMaxX())
2935
4378
                                {
2936
4379
                                        nX = nr.routeBounds.getMaxX();
2937
 
                                        if (!inDestGrid(toRectGridded, nX, curY)) nX = nr.getLowerXGrid(curZ, nX);
 
4380
                                        if (!inDestGrid(toRectGridded, nX, curY)) nX = nr.getLowerXGrid(curZ, nX).getCoordinate();
2938
4381
                                        dx = nX - curX;
2939
4382
                                        if (dx == 0)
2940
4383
                                        {
2941
 
                                                if (RoutingDebug.isActive()) completeDebugString(i, ": Out Of X Bounds");
 
4384
                                                if (debuggingWavefront) completeDebugString(i, ": Out Of X Bounds");
2942
4385
                                                continue;
2943
4386
                                        }
2944
4387
                                }
2945
4388
                                if (nY < nr.routeBounds.getMinY())
2946
4389
                                {
2947
4390
                                        nY = nr.routeBounds.getMinY();
2948
 
                                        if (!inDestGrid(toRectGridded, curX, nY)) nY = nr.getUpperYGrid(curZ, nY);
 
4391
                                        if (!inDestGrid(toRectGridded, curX, nY)) nY = nr.getUpperYGrid(curZ, nY).getCoordinate();
2949
4392
                                        dy = nY - curY;
2950
4393
                                        if (dy == 0)
2951
4394
                                        {
2952
 
                                                if (RoutingDebug.isActive()) completeDebugString(i, ": Out Of Y Bounds");
 
4395
                                                if (debuggingWavefront) completeDebugString(i, ": Out Of Y Bounds");
2953
4396
                                                continue;
2954
4397
                                        }
2955
4398
                                }
2956
4399
                                if (nY > nr.routeBounds.getMaxY())
2957
4400
                                {
2958
4401
                                        nY = nr.routeBounds.getMaxY();
2959
 
                                        if (!inDestGrid(toRectGridded, curX, nY)) nY = nr.getLowerYGrid(curZ, nY);
 
4402
                                        if (!inDestGrid(toRectGridded, curX, nY)) nY = nr.getLowerYGrid(curZ, nY).getCoordinate();
2960
4403
                                        dy = nY - curY;
2961
4404
                                        if (dy == 0)
2962
4405
                                        {
2963
 
                                                if (RoutingDebug.isActive()) completeDebugString(i, ": Out Of Y Bounds");
 
4406
                                                if (debuggingWavefront) completeDebugString(i, ": Out Of Y Bounds");
2964
4407
                                                continue;
2965
4408
                                        }
2966
4409
                                }
2967
 
                                if (nZ < 0 || nZ >= numMetalLayers)
2968
 
                                {
2969
 
                                        if (RoutingDebug.isActive()) completeDebugString(i, ": Out Of Bounds");
2970
 
                                        continue;
2971
 
                                }
2972
 
                                if (nr.preventArc(nZ))
2973
 
                                {
2974
 
                                        if (RoutingDebug.isActive()) completeDebugString(i, ": Disallowed Arc");
2975
 
                                        continue;
2976
 
                                }
2977
4410
 
2978
4411
                                // see if the point has already been visited
2979
4412
                                SearchVertex alreadyThere = getVertex(nX, nY, nZ);
2981
4414
                                {
2982
4415
                                        if (!active.inList(alreadyThere))
2983
4416
                                        {
2984
 
                                                if (RoutingDebug.isActive()) completeDebugString(i, ": Already Visited");
 
4417
                                                if (debuggingWavefront) completeDebugString(i, ": Already Visited");
2985
4418
                                                continue;
2986
4419
                                        }
2987
4420
                                }
2988
4421
 
2989
4422
                                // see if the space is available
2990
4423
                                int whichContact = 0;
2991
 
                                Point2D[] cuts = null;
 
4424
                                Rectangle2D[] cuts = null;
2992
4425
                                Point2D size = null;
 
4426
                                SearchVertexAddon extraGeometryforMinArea = null;
2993
4427
                                if (dz == 0)
2994
4428
                                {
2995
4429
                                        // running on one layer: check surround
2996
 
                                        double width = nr.getArcWidth(nZ);
 
4430
                                        double width = nr.getArcWidth(nZ, curX, curY, nX, nY);
2997
4431
                                        double metalSpacing = width / 2;
2998
4432
                                        boolean allClear = false;
2999
4433
                                        double initNX = nX, initNY = nY;
3000
4434
                                        String explanation = null;
3001
 
                                        if (RoutingDebug.isActive()) explanation = "";
 
4435
                                        if (debuggingWavefront) explanation = "";
3002
4436
                                        for(;;)
3003
4437
                                        {
3004
4438
                                                SearchVertex prevPath = svCurrent;
3021
4455
                                                        } else
3022
4456
                                                                break;
3023
4457
                                                }
3024
 
                                                SOGBound sb = getMetalBlockageAndNotch(nZ, halfWid, halfHei, checkX, checkY, prevPath);
 
4458
                                                SOGBound sb = getMetalBlockageAndNotch(nZ, nC, halfWid, halfHei, checkX, checkY, prevPath, false);
3025
4459
                                                if (sb == null)
3026
4460
                                                {
3027
4461
                                                        allClear = true;
3028
4462
                                                        break;
3029
4463
                                                }
3030
 
                                                if (RoutingDebug.isActive())
3031
 
                                                        explanation += ": Blocked on M" + (nZ+1) + " because proposed " +
3032
 
                                                                TextUtils.formatDouble(checkX-halfWid) +
3033
 
                                                                "<=X<=" + TextUtils.formatDouble(checkX+halfWid) +
3034
 
                                                                " and " + TextUtils.formatDouble(checkY-halfHei) +
3035
 
                                                                "<=Y<=" + TextUtils.formatDouble(checkY+halfHei) +
3036
 
                                                                " is less than " + TextUtils.formatDouble(metalSpacing) +
3037
 
                                                                " to " + TextUtils.formatDouble(sb.bound.getMinX()) +
3038
 
                                                                "<=X<=" + TextUtils.formatDouble(sb.bound.getMaxX()) +
3039
 
                                                                " and " + TextUtils.formatDouble(sb.bound.getMinY()) +
3040
 
                                                                "<=Y<=" + TextUtils.formatDouble(sb.bound.getMaxY());
 
4464
                                                if (debuggingWavefront)
 
4465
                                                        explanation += ": Blocked on " + describeMetal(nZ,nC) + " because proposed " +
 
4466
                                                                TextUtils.formatDistance(checkX-halfWid) + "<=X<=" + TextUtils.formatDistance(checkX+halfWid) +
 
4467
                                                                " and " + TextUtils.formatDistance(checkY-halfHei) + "<=Y<=" + TextUtils.formatDistance(checkY+halfHei) +
 
4468
                                                                " is less than " + TextUtils.formatDistance(metalSpacing) +
 
4469
                                                                " to " + TextUtils.formatDistance(sb.bound.getMinX()) + "<=X<=" + TextUtils.formatDistance(sb.bound.getMaxX()) +
 
4470
                                                                " and " + TextUtils.formatDistance(sb.bound.getMinY()) + "<=Y<=" + TextUtils.formatDistance(sb.bound.getMaxY());
3041
4471
 
3042
4472
                                                // see if it can be backed out slightly
3043
4473
                                                if (i == 0)
3044
4474
                                                {
3045
4475
                                                        // moved left too far...try a bit to the right
3046
4476
                                                        double newNX = nX + GRAINSIZE;
3047
 
                                                        if (inDestGrid(toRectGridded, newNX, curY)) newNX = nr.downToGrainAlways(newNX); else
3048
 
                                                                newNX = nr.getUpperXGrid(curZ, newNX);
 
4477
                                                        if (!nr.forceGridArcs[nZ] && inDestGrid(toRectGridded, newNX, curY)) newNX = nr.downToGrainAlways(newNX); else
 
4478
                                                                newNX = nr.getUpperXGrid(curZ, newNX).getCoordinate();
3049
4479
                                                        if (newNX >= curX || DBMath.areEquals(newNX, nX)) break;
3050
4480
                                                        dx = newNX - curX;
3051
4481
                                                        if (dx == 0) break;
3053
4483
                                                {
3054
4484
                                                        // moved right too far...try a bit to the left
3055
4485
                                                        double newNX = nX - GRAINSIZE;
3056
 
                                                        if (inDestGrid(toRectGridded, newNX, curY)) newNX = nr.upToGrainAlways(newNX); else
3057
 
                                                                newNX = nr.getLowerXGrid(curZ, newNX);
 
4486
                                                        if (!nr.forceGridArcs[nZ] && inDestGrid(toRectGridded, newNX, curY)) newNX = nr.upToGrainAlways(newNX); else
 
4487
                                                                newNX = nr.getLowerXGrid(curZ, newNX).getCoordinate();
3058
4488
                                                        if (newNX <= curX || DBMath.areEquals(newNX, nX)) break;
3059
4489
                                                        dx = newNX - curX;
3060
4490
                                                        if (dx == 0) break;
3062
4492
                                                {
3063
4493
                                                        // moved down too far...try a bit up
3064
4494
                                                        double newNY = nY + GRAINSIZE;
3065
 
                                                        if (inDestGrid(toRectGridded, curX, newNY)) newNY = nr.downToGrainAlways(newNY); else
3066
 
                                                                newNY = nr.getUpperYGrid(curZ, newNY);
 
4495
                                                        if (!nr.forceGridArcs[nZ] && inDestGrid(toRectGridded, curX, newNY)) newNY = nr.downToGrainAlways(newNY); else
 
4496
                                                                newNY = nr.getUpperYGrid(curZ, newNY).getCoordinate();
3067
4497
                                                        if (newNY >= curY || DBMath.areEquals(newNY, nY)) break;
3068
4498
                                                        dy = newNY - curY;
3069
4499
                                                        if (dy == 0) break;
3071
4501
                                                {
3072
4502
                                                        // moved up too far...try a bit down
3073
4503
                                                        double newNY = nY - GRAINSIZE;
3074
 
                                                        if (inDestGrid(toRectGridded, curX, newNY)) newNY = nr.upToGrainAlways(newNY); else
3075
 
                                                                newNY = nr.getLowerYGrid(curZ, newNY);
 
4504
                                                        if (!nr.forceGridArcs[nZ] && inDestGrid(toRectGridded, curX, newNY)) newNY = nr.upToGrainAlways(newNY); else
 
4505
                                                                newNY = nr.getLowerYGrid(curZ, newNY).getCoordinate();
3076
4506
                                                        if (newNY <= curY || DBMath.areEquals(newNY, nY)) break;
3077
4507
                                                        dy = newNY - curY;
3078
4508
                                                        if (dy == 0) break;
3083
4513
                                        }
3084
4514
                                        if (!allClear)
3085
4515
                                        {
3086
 
                                                if (RoutingDebug.isActive())
 
4516
                                                if (debuggingWavefront)
3087
4517
                                                {
3088
4518
                                                        double checkX = (curX + nX) / 2, checkY = (curY + nY) / 2;
3089
4519
                                                        double halfWid = metalSpacing + Math.abs(dx) / 2;
3090
4520
                                                        double halfHei = metalSpacing + Math.abs(dy) / 2;
3091
 
                                                        double surround = worstMetalSurround[nZ];
3092
 
                                                        SOGBound sb = nr.getMetalBlockage(nr.netID, nZ, halfWid, halfHei, new double[] {surround, surround}, checkX, checkY);
 
4521
 
 
4522
                                                        double[] surround = nr.getSpacingRule(nZ, maxDefArcWidth[nZ], -1);
 
4523
                                                        SOGBound sb = nr.getMetalBlockage(nr.netID, nZ, halfWid, halfHei, surround, checkX, checkY);
3093
4524
                                                        if (sb != null) explanation += ": Blocked"; else
3094
4525
                                                                explanation += ": Blocked, Notch";
3095
4526
                                                        completeDebugString(i, explanation);
3096
4527
                                                }
3097
4528
                                                continue;
3098
4529
                                        }
3099
 
                                        if (RoutingDebug.isActive())
 
4530
                                        if (debuggingWavefront)
3100
4531
                                        {
3101
4532
                                                if (initNX != nX || initNY != nY)
3102
4533
                                                {
3103
4534
                                                        explanation += " so move only ";
3104
4535
                                                        switch (i)
3105
4536
                                                        {
3106
 
                                                                case 0: explanation += TextUtils.formatDouble(Math.abs(dx));  break;
3107
 
                                                                case 1: explanation += TextUtils.formatDouble(dx);            break;
3108
 
                                                                case 2: explanation += TextUtils.formatDouble(Math.abs(dy));  break;
3109
 
                                                                case 3: explanation += TextUtils.formatDouble(dy);            break;
 
4537
                                                                case 0: explanation += TextUtils.formatDistance(Math.abs(dx));  break;
 
4538
                                                                case 1: explanation += TextUtils.formatDistance(dx);            break;
 
4539
                                                                case 2: explanation += TextUtils.formatDistance(Math.abs(dy));  break;
 
4540
                                                                case 3: explanation += TextUtils.formatDistance(dy);            break;
3110
4541
                                                        }
3111
4542
                                                }
3112
4543
                                                addDebugString(i, explanation);
3117
4548
                                        int lowMetal = Math.min(curZ, nZ);
3118
4549
                                        int highMetal = Math.max(curZ, nZ);
3119
4550
                                        List<MetalVia> nps = metalVias[lowMetal].getVias();
 
4551
                                        if (nr.is2X(lowMetal, curX, curY, nX, nY) || nr.is2X(highMetal, curX, curY, nX, nY))
 
4552
                                        {
 
4553
                                                List<MetalVia> nps2X = metalVias2X[lowMetal].getVias();
 
4554
                                                if (nps2X.size() > 0) nps = nps2X;
 
4555
                                        }
3120
4556
                                        whichContact = -1;
3121
4557
                                        String[] failureReasons = null;
3122
 
                                        if (RoutingDebug.isActive()) failureReasons = new String[nps.size()];
 
4558
                                        if (debuggingWavefront) failureReasons = new String[nps.size()];
3123
4559
                                        for (int contactNo = 0; contactNo < nps.size(); contactNo++)
3124
4560
                                        {
3125
4561
                                                MetalVia mv = nps.get(contactNo);
 
4562
                                                if (mv.horMetal == curZ)
 
4563
                                                {
 
4564
                                                        if (mv.horMetalColor != curC || mv.verMetalColor != nC)
 
4565
                                                        {
 
4566
                                                                if (debuggingWavefront) failureReasons[contactNo] = "masks are " + mv.horMetalColor + " and " +
 
4567
                                                                        mv.verMetalColor + " but want masks " + curC + " and " + nC;
 
4568
                                                                continue;
 
4569
                                                        }
 
4570
                                                } else if (mv.verMetal == curZ)
 
4571
                                                {
 
4572
                                                        if (mv.verMetalColor != curC || mv.horMetalColor != nC)
 
4573
                                                        {
 
4574
                                                                if (debuggingWavefront) failureReasons[contactNo] = "masks are " + mv.verMetalColor + " and " +
 
4575
                                                                        mv.horMetalColor + " but want masks " + curC + " and " + nC;
 
4576
                                                                continue;
 
4577
                                                        }
 
4578
                                                }
 
4579
                                                MutableDouble conWid = new MutableDouble(0), conHei = new MutableDouble(0);
 
4580
                                                double lastX = nX, lastY = nY;
 
4581
                                                SearchVertex prev = svCurrent.getLast();
 
4582
                                                if (prev != null)
 
4583
                                                {
 
4584
                                                        lastX = prev.getX();
 
4585
                                                        lastY = prev.getY();
 
4586
                                                        if (closeToEnd && (lastX != fromX || lastY != fromY))
 
4587
                                                        {
 
4588
                                                                lastX = toX;
 
4589
                                                                lastY = toY;
 
4590
                                                        }
 
4591
                                                }
 
4592
                                                Orientation orient = nr.getMVSize(mv, nX, nY, lastX, lastY, conWid, conHei);
3126
4593
                                                PrimitiveNode np = mv.via;
3127
 
                                                Orientation orient = Orientation.fromJava(mv.orientation * 10, false, false);
3128
 
                                                SizeOffset so = np.getProtoSizeOffset();
3129
 
                                                double minWid = nr.minWidth;
3130
 
                                                double minHei = nr.minWidth;
3131
 
                                                double xOffset = so.getLowXOffset() + so.getHighXOffset();
3132
 
                                                double yOffset = so.getLowYOffset() + so.getHighYOffset();
3133
 
                                                double conWid = Math.max(np.getDefWidth(ep) - xOffset, minWid) + xOffset;
3134
 
                                                double conHei = Math.max(np.getDefHeight(ep) - yOffset, minHei) + yOffset;
3135
 
                                                boolean allowOverrides = false;
3136
 
                                                if (mv.horMetal >= 0 && mv.verMetal >= 0)
3137
 
                                                {
3138
 
                                                        if (sogp.isHorizontalEven())
3139
 
                                                        {
3140
 
                                                                if ((mv.horMetal+1)%2 == 0) allowOverrides = true;
3141
 
                                                        } else
3142
 
                                                        {
3143
 
                                                                if ((mv.verMetal+1)%2 != 0) allowOverrides = true;
3144
 
                                                        }
3145
 
                                                }
3146
 
                                                if (allowOverrides)
3147
 
                                                {
3148
 
                                                        xOffset = mv.verMetalInset;
3149
 
                                                        yOffset = mv.horMetalInset;
3150
 
                                                        if (nr.getArcWidth(mv.verMetal) + xOffset > conWid) conWid = nr.getArcWidth(mv.verMetal) + xOffset;
3151
 
                                                        if (nr.getArcWidth(mv.horMetal) + yOffset > conHei) conHei = nr.getArcWidth(mv.horMetal) + yOffset;
3152
 
                                                }
3153
 
                                                NodeInst dummyNi = NodeInst.makeDummyInstance(np, ep, EPoint.fromLambda(nX, nY), conWid, conHei, orient);
 
4594
                                                NodeInst dummyNi = NodeInst.makeDummyInstance(np, ep, EPoint.fromLambda(nX, nY), conWid.doubleValue(), conHei.doubleValue(), orient);
3154
4595
                                                Poly[] conPolys = tech.getShapeOfNode(dummyNi);
3155
4596
                                                FixpTransform trans = null;
3156
4597
                                                if (orient != Orientation.IDENT) trans = dummyNi.rotateOut();
3159
4600
                                                int cutCount = 0;
3160
4601
                                                for (int p = 0; p < conPolys.length; p++)
3161
4602
                                                        if (conPolys[p].getLayer().getFunction().isContact()) cutCount++;
3162
 
                                                Point2D[] curCuts = new Point2D[cutCount];
 
4603
                                                Rectangle2D[] curCuts = new Rectangle2D[cutCount];
3163
4604
                                                cutCount = 0;
3164
4605
                                                String failedReason = null;
 
4606
                                                boolean contactFailed = false;
3165
4607
                                                for (int p = 0; p < conPolys.length; p++)
3166
4608
                                                {
3167
4609
                                                        Poly conPoly = conPolys[p];
3172
4614
                                                        {
3173
4615
                                                                Rectangle2D conRect = conPoly.getBounds2D();
3174
4616
                                                                int metalNo = lFun.getLevel() - 1;
 
4617
                                                                int maskNo = lFun.getMaskColor();
3175
4618
                                                                double halfWid = conRect.getWidth() / 2;
3176
4619
                                                                double halfHei = conRect.getHeight() / 2;
3177
 
                                                                SOGBound sb = getMetalBlockageAndNotch(metalNo, halfWid, halfHei, conRect.getCenterX(), conRect.getCenterY(), svCurrent);
 
4620
                                                                SOGBound sb = getMetalBlockageAndNotch(metalNo, maskNo, halfWid, halfHei, conRect.getCenterX(), conRect.getCenterY(), svCurrent, false);
3178
4621
                                                                if (sb != null)
3179
4622
                                                                {
3180
 
                                                                        if (failureReasons == null) failedReason = ""; else
 
4623
                                                                        contactFailed = true;
 
4624
                                                                        if (debuggingWavefront)
3181
4625
                                                                        {
3182
 
                                                                                failedReason = "layer " + conLayer.getName();
3183
 
                                                                                failedReason +=
3184
 
                                                                                        " at " + TextUtils.formatDouble(conRect.getMinX()) +
3185
 
                                                                                        "<=X<=" + TextUtils.formatDouble(conRect.getMaxX()) +
3186
 
                                                                                        " and " + TextUtils.formatDouble(conRect.getMinY()) +
3187
 
                                                                                        "<=Y<=" + TextUtils.formatDouble(conRect.getMaxY());
3188
 
                                                                                failedReason +=
3189
 
                                                                                        " conflicts with " + TextUtils.formatDouble(sb.getBounds().getMinX()) +
3190
 
                                                                                        "<=X<=" + TextUtils.formatDouble(sb.getBounds().getMaxX()) +
3191
 
                                                                                        " and " + TextUtils.formatDouble(sb.getBounds().getMinY()) +
3192
 
                                                                                        "<=Y<=" + TextUtils.formatDouble(sb.getBounds().getMaxY());
 
4626
                                                                                failedReason = "layer " + conLayer.getName() +
 
4627
                                                                                        " at " + TextUtils.formatDistance(conRect.getMinX()) + "<=X<=" + TextUtils.formatDistance(conRect.getMaxX()) +
 
4628
                                                                                        " and " + TextUtils.formatDistance(conRect.getMinY()) + "<=Y<=" + TextUtils.formatDistance(conRect.getMaxY()) +
 
4629
                                                                                        " conflicts with " + TextUtils.formatDistance(sb.getBounds().getMinX()) + "<=X<=" + TextUtils.formatDistance(sb.getBounds().getMaxX()) +
 
4630
                                                                                        " and " + TextUtils.formatDistance(sb.getBounds().getMinY()) + "<=Y<=" + TextUtils.formatDistance(sb.getBounds().getMaxY());
3193
4631
                                                                        }
3194
4632
                                                                        break;
3195
4633
                                                                }
3200
4638
                                                                double conCX = conRect.getCenterX();
3201
4639
                                                                double conCY = conRect.getCenterY();
3202
4640
                                                                double surround = viaSurround[lowMetal];
3203
 
                                                                if (nr.getViaBlockage(nr.netID, conLayer, surround, surround, conCX, conCY) != null)
 
4641
                                                                double vSize = viaSize[lowMetal];
 
4642
                                                                SOGVia sb = NEWVIACALC ? nr.getViaBlockage(nr.netID, conLayer, surround, conRect) :
 
4643
                                                                        nr.getViaBlockageOLD(nr.netID, conLayer, surround+vSize, surround+vSize, conCX, conCY);
 
4644
                                                                if (sb != null)
3204
4645
                                                                {
3205
 
                                                                        if (failureReasons == null) failedReason = ""; else
 
4646
                                                                        contactFailed = true;
 
4647
                                                                        if (debuggingWavefront)
 
4648
                                                                        {
3206
4649
                                                                                failedReason = "cut " + conLayer.getName() +
3207
 
                                                                                        " at " + TextUtils.formatDouble(conRect.getMinX()) +
3208
 
                                                                                        "<=X<=" + TextUtils.formatDouble(conRect.getMaxX()) +
3209
 
                                                                                        " and " + TextUtils.formatDouble(conRect.getMinY()) +
3210
 
                                                                                        "<=Y<=" + TextUtils.formatDouble(conRect.getMaxY());
 
4650
                                                                                        " at " + TextUtils.formatDistance(conRect.getMinX()) + "<=X<=" + TextUtils.formatDistance(conRect.getMaxX()) +
 
4651
                                                                                        " and " + TextUtils.formatDistance(conRect.getMinY()) + "<=Y<=" + TextUtils.formatDistance(conRect.getMaxY()) +
 
4652
                                                                                        " less than "+TextUtils.formatDistance(surround)+" to cut at (" +
 
4653
                                                                                        TextUtils.formatDistance(sb.getBounds().getCenterX()) + "," + TextUtils.formatDistance(sb.getBounds().getCenterY()) + ")";
 
4654
                                                                        }
3211
4655
                                                                        break;
3212
4656
                                                                }
3213
 
                                                                curCuts[cutCount++] = new Point2D.Double(conCX, conCY);
 
4657
                                                                curCuts[cutCount++] = new Rectangle2D.Double(conRect.getMinX(), conRect.getMinY(), conRect.getWidth(), conRect.getHeight());
3214
4658
 
3215
4659
                                                                // look at all previous cuts in this path
3216
4660
                                                                for (SearchVertex sv = svCurrent; sv != null; sv = sv.last)
3221
4665
                                                                                Math.max(sv.getZ(), lastSv.getZ()) == highMetal)
3222
4666
                                                                        {
3223
4667
                                                                                // make sure the cut isn't too close
3224
 
                                                                                Point2D[] svCuts;
3225
 
                                                                                if (sv.getCutLayer() == lowMetal) svCuts = sv.getCuts(); else
3226
 
                                                                                        svCuts = lastSv.getCuts();
3227
 
                                                                                if (svCuts != null)
 
4668
                                                                                Rectangle2D[] svCutRects;
 
4669
                                                                                if (sv.getCutLayer() == lowMetal) svCutRects = sv.getCutRects(); else
 
4670
                                                                                        svCutRects = lastSv.getCutRects();
 
4671
                                                                                if (svCutRects != null)
3228
4672
                                                                                {
3229
 
                                                                                        for (Point2D cutPt : svCuts)
 
4673
                                                                                        for (Rectangle2D cutRect : svCutRects)
3230
4674
                                                                                        {
3231
 
                                                                                                if (Math.abs(cutPt.getX() - conCX) >= surround ||
3232
 
                                                                                                        Math.abs(cutPt.getY() - conCY) >= surround) continue;
3233
 
                                                                                                if (failureReasons == null) failedReason = ""; else
3234
 
                                                                                                        failedReason = conLayer.getName() + " cut at (" + TextUtils.formatDouble(conCX) + "," +
3235
 
                                                                                                                TextUtils.formatDouble(conCY) + ") because it is too close (" + surround + ") to previous cut at (" +
3236
 
                                                                                                                TextUtils.formatDouble(sv.getX()) + "," + TextUtils.formatDouble(sv.getY()) + ")";
 
4675
                                                                                                double dist = cutDistance(conRect.getMinX(), conRect.getMaxX(), conRect.getMinY(), conRect.getMaxY(),
 
4676
                                                                                                        cutRect.getMinX(), cutRect.getMaxX(), cutRect.getMinY(), cutRect.getMaxY());
 
4677
                                                                                                boolean newSafe = DBMath.isGreaterThanOrEqualTo(dist, surround);
 
4678
                                                                                                boolean oldSafe = Math.abs(cutRect.getCenterX() - conCX) >= surround+vSize ||
 
4679
                                                                                                        Math.abs(cutRect.getCenterY() - conCY) >= surround+vSize;
 
4680
                                                                                                if (NEWVIACALC)
 
4681
                                                                                                {
 
4682
                                                                                                        if (newSafe) continue;
 
4683
                                                                                                } else
 
4684
                                                                                                {
 
4685
                                                                                                        if (oldSafe) continue;
 
4686
                                                                                                }
 
4687
                                                                                                contactFailed = true;
 
4688
                                                                                                if (debuggingWavefront)
 
4689
                                                                                                        failedReason = conLayer.getName() + " cut at (" + TextUtils.formatDistance(conCX) + "," +
 
4690
                                                                                                                TextUtils.formatDistance(conCY) + ") because it is too close (" + surround + ") to previous cut at (" +
 
4691
                                                                                                                TextUtils.formatDistance(sv.getX()) + "," + TextUtils.formatDistance(sv.getY()) + ")";
3237
4692
                                                                                                break;
3238
4693
                                                                                        }
3239
4694
                                                                                }
3240
 
                                                                                if (failedReason != null) break;
 
4695
                                                                                if (contactFailed) break;
3241
4696
                                                                        }
3242
4697
                                                                }
3243
 
                                                                if (failedReason != null) break;
3244
 
                                                        }
3245
 
                                                }
3246
 
                                                if (failedReason != null)
3247
 
                                                {
3248
 
                                                        if (RoutingDebug.isActive()) failureReasons[contactNo] = failedReason;
3249
 
                                                        continue;
3250
 
                                                }
 
4698
                                                                if (contactFailed) break;
 
4699
                                                        }
 
4700
                                                }
 
4701
                                                if (contactFailed)
 
4702
                                                {
 
4703
                                                        if (debuggingWavefront) failureReasons[contactNo] = failedReason;
 
4704
                                                        continue;
 
4705
                                                }
 
4706
 
 
4707
                                                // see if previous metal meets minimum area considerations
 
4708
                                                StringBuffer message = new StringBuffer();
 
4709
                                                MutableBoolean error = new MutableBoolean(false);
 
4710
                                                extraGeometryforMinArea = determineMinimumArea(svCurrent, curX, curY, curC, curZ, mv, conWid.doubleValue(), conHei.doubleValue(), error, message);
 
4711
                                                if (error.booleanValue())
 
4712
                                                {
 
4713
                                                        if (message.length() > 0)
 
4714
                                                        {
 
4715
                                                                contactFailed = true;
 
4716
                                                                if (debuggingWavefront)
 
4717
                                                                        failureReasons[contactNo] = message.toString();
 
4718
                                                        }
 
4719
                                                        continue;
 
4720
                                                }
 
4721
 
3251
4722
                                                whichContact = contactNo;
3252
4723
                                                cuts = curCuts;
3253
 
                                                size = new Point2D.Double(conWid, conHei);
 
4724
                                                size = new Point2D.Double(conWid.doubleValue(), conHei.doubleValue());
3254
4725
                                                break;
3255
4726
                                        }
3256
4727
                                        if (whichContact < 0)
3257
4728
                                        {
3258
 
                                                if (RoutingDebug.isActive())
 
4729
                                                if (debuggingWavefront)
3259
4730
                                                {
3260
4731
                                                        String further = ": Blocked because:";
3261
4732
                                                        for(int contactNo = 0; contactNo < failureReasons.length; contactNo++)
3263
4734
                                                                MetalVia mv = nps.get(contactNo);
3264
4735
                                                                further += "|In " + describe(mv.via);
3265
4736
                                                                if (mv.orientation != 0) further += " (rotated " + mv.orientation + ")";
3266
 
                                                                further += " cannot place " + failureReasons[contactNo];
 
4737
                                                                further += " cannot place: " + failureReasons[contactNo];
3267
4738
                                                        }
3268
4739
                                                        completeDebugString(i, further);
3269
4740
                                                }
3273
4744
 
3274
4745
                                // see if it found the destination
3275
4746
                                boolean foundDest = DBMath.pointInRect(EPoint.fromLambda(nX, nY), toRect) && nZ == toZ;
3276
 
 
3277
 
                                if (foundDestination != null)
3278
 
                                        foundDest = true;
3279
 
 
3280
 
                                // ignore if a large jump on the wrong metal layer
3281
 
                                if (foundDest)
3282
 
                                {
3283
 
                                        if (Math.abs(dx) > 10 && (nZ % 2) == 0) continue;
3284
 
                                        if (Math.abs(dy) > 10 && (nZ % 2) != 0) continue;
 
4747
                                if (svCurrent.isMustCompleteRoute() && !foundDest)
 
4748
                                {
 
4749
                                        if (debuggingWavefront) completeDebugString(i, ": Switched to taper layer so must connect to destination");
 
4750
                                        continue;
 
4751
                                }
 
4752
                                if (svCurrent.isCantCompleteRoute() && foundDest)
 
4753
                                {
 
4754
                                        if (debuggingWavefront) completeDebugString(i, ": Switched to taper layer too far from destination");
 
4755
                                        continue;
 
4756
                                }
 
4757
 
 
4758
                                // check for minimum area in final segment TODO: finish this
 
4759
//                              if (foundDest)
 
4760
//                              {
 
4761
//                                      StringBuffer message = new StringBuffer();
 
4762
//                                      MutableBoolean error = new MutableBoolean(false);
 
4763
//                                      extraGeometryforMinArea = determineMinimumArea(svCurrent, curX, curY, curC, curZ, null, 0, 0, error, message);
 
4764
//                                      if (error.booleanValue())
 
4765
//                                      {
 
4766
//                                              if (message.length() > 0)
 
4767
//                                              {
 
4768
//                                                      if (debuggingWavefront)
 
4769
//                                                              completeDebugString(i, message.toString());
 
4770
//                                              }
 
4771
//                                              continue;
 
4772
//                                      }
 
4773
//                              }
 
4774
 
 
4775
                                // check for off-grid situations
 
4776
                                boolean hor = true;
 
4777
                                if (sogp.isHorizontalEven())
 
4778
                                {
 
4779
                                        if (((nZ+1)%2) != 0) hor = false;
 
4780
                                } else
 
4781
                                {
 
4782
                                        if (((nZ+1)%2) == 0) hor = false;
 
4783
                                }
 
4784
 
 
4785
                                // reject if not on grid and grid is forced
 
4786
                                if (nr.forceGridArcs[nZ] && !foundDest)
 
4787
                                {
 
4788
                                        if (nr.gridLocationsX[nZ] != null && (hor && !nr.isOnXGrid(nZ, nX)))
 
4789
                                        {
 
4790
                                                if (debuggingWavefront) completeDebugString(i, ": Not on X grid");
 
4791
                                                continue;
 
4792
                                        }
 
4793
                                        if (nr.gridLocationsY[nZ] != null && (!hor && !nr.isOnYGrid(nZ, nY)))
 
4794
                                        {
 
4795
                                                if (debuggingWavefront) completeDebugString(i, ": Not on Y grid");
 
4796
                                                continue;
 
4797
                                        }
 
4798
                                }
 
4799
 
 
4800
                                // determine if off-grid
 
4801
                                boolean penaltyOffGridX = false;
 
4802
                                boolean inGoalX = nX < toRect.getMinX() || nX > toRect.getMaxX();
 
4803
                                if (NOGRIDPENALTYATSOURCE) inGoalX &= nX != fromX;
 
4804
                                if (inGoalX || nr.forceGridArcs[nZ])
 
4805
                                {
 
4806
                                        if (nr.gridLocationsX[nZ] == null)
 
4807
                                        {
 
4808
                                                penaltyOffGridX = nr.downToGrainAlways(nX) != nX;
 
4809
                                        } else if (!hor)
 
4810
                                        {
 
4811
                                                penaltyOffGridX = !nr.isOnXGrid(nZ, nX);
 
4812
                                        }
 
4813
                                }
 
4814
                                boolean penaltyOffGridY = false;
 
4815
                                boolean inGoalY = nY < toRect.getMinY() || nY > toRect.getMaxY();
 
4816
                                if (NOGRIDPENALTYATSOURCE) inGoalY &= nY != fromY;
 
4817
                                if (inGoalY || nr.forceGridArcs[nZ])
 
4818
                                {
 
4819
                                        if (nr.gridLocationsY[nZ] == null)
 
4820
                                        {
 
4821
                                                penaltyOffGridY = nr.downToGrainAlways(nY) != nY;
 
4822
                                        } else if (hor)
 
4823
                                        {
 
4824
                                                penaltyOffGridY = !nr.isOnYGrid(nZ, nY);
 
4825
                                        }
3285
4826
                                }
3286
4827
 
3287
4828
                                // we have a candidate next-point
3288
 
                                SearchVertex svNext = new SearchVertex(nX, nY, nZ, whichContact, cuts, size, Math.min(curZ, nZ), this);
 
4829
                                int newFlags = svCurrent.flags;
 
4830
                                if (curZ != nZ) newFlags &= ~SearchVertex.TOOFARFROMEND;
 
4831
                                if (dz != 0) newFlags |= SearchVertex.OFFINITIALSEGMENT;
 
4832
                                if (tooFarFromEnd) newFlags |= SearchVertex.TOOFARFROMEND;
 
4833
                                if (closeToEnd) newFlags |= SearchVertex.CLOSETOEND;
 
4834
                                SearchVertex svNext = new SearchVertex(nX, nY, nZ, nC, whichContact, cuts, size, Math.min(curZ, nZ), this, newFlags);
 
4835
                                if (debuggingWavefront) RoutingDebug.ensureDebuggingShadow(svNext, false);
 
4836
                                if (extraGeometryforMinArea != null)
 
4837
                                        svNext.setMoreGeometry(extraGeometryforMinArea);
3289
4838
                                if (dz == 0 && (Math.abs(dx) >= 2 || Math.abs(dy) >= 2)) svNext.setAutoGen(i);
3290
4839
                                svNext.last = svCurrent;
3291
4840
 
3292
4841
                                if (foundDest)
3293
4842
                                {
3294
 
                                        if (RoutingDebug.isActive())
 
4843
                                        if (debuggingWavefront)
3295
4844
                                        {
3296
4845
                                                RoutingDebug.saveSVLink(svNext, i);
3297
4846
                                                completeDebugString(i, ": Found Destination!");
3307
4856
                                // compute the cost
3308
4857
                                int newCost = svCurrent.cost;
3309
4858
                                String costExplanation = "";
3310
 
                                boolean penaltyOffGridX = false;
3311
 
                                if (nX < toRect.getMinX() || nX > toRect.getMaxX())
3312
 
                                {
3313
 
                                        if (nr.gridLocationsX[nZ] == null)
3314
 
                                        {
3315
 
                                                penaltyOffGridX = nr.downToGrainAlways(nX) != nX;
3316
 
                                        } else
3317
 
                                        {
3318
 
                                                penaltyOffGridX = !nr.isOnXGrid(nZ, nX);
3319
 
                                        }
3320
 
                                }
3321
 
                                boolean penaltyOffGridY = false;
3322
 
                                if (nY < toRect.getMinY() || nY > toRect.getMaxY())
3323
 
                                {
3324
 
                                        if (nr.gridLocationsY[nZ] == null)
3325
 
                                        {
3326
 
                                                penaltyOffGridY = nr.downToGrainAlways(nY) != nY;
3327
 
                                        } else
3328
 
                                        {
3329
 
                                                penaltyOffGridY = !nr.isOnYGrid(nZ, nY);
3330
 
                                        }
3331
 
                                }
3332
 
 
3333
4859
                                double distBefore = Math.sqrt((curX-toX)*(curX-toX) + (curY-toY)*(curY-toY));
3334
4860
                                double distAfter = Math.sqrt((nX-toX)*(nX-toX) + (nY-toY)*(nY-toY));
3335
4861
                                int c = (int)((distAfter - distBefore) / 5);
3336
4862
                                newCost += c;
3337
 
                                if (RoutingDebug.isActive()) costExplanation = " [COST: Dist-to-target=" + c;
 
4863
                                if (debuggingWavefront) costExplanation = " [COST: Progress-to-target=" + c;
3338
4864
 
3339
4865
                                if (dx != 0)
3340
4866
                                {
3342
4868
                                        {
3343
4869
                                                c = COSTWRONGDIRECTION / 2;
3344
4870
                                                newCost += c;
3345
 
                                                if (RoutingDebug.isActive()) costExplanation += " Zero-X-progress=" + c;
 
4871
                                                if (debuggingWavefront) costExplanation += " Zero-X-progress=" + c;
3346
4872
                                        } else if ((toX - curX) * dx < 0)
3347
4873
                                        {
3348
4874
                                                if (curY >= toRect.getMinY() && curY <= toRect.getMaxY())
3349
4875
                                                {
3350
4876
                                                        c = 1;
3351
4877
                                                        newCost += c;
3352
 
                                                        if (RoutingDebug.isActive()) costExplanation += " Backward-X-progress-at-dest-Y=" + c;
 
4878
                                                        if (debuggingWavefront) costExplanation += " Backward-X-progress-at-dest-Y=" + c;
3353
4879
                                                } else
3354
4880
                                                {
3355
4881
                                                        c = COSTWRONGDIRECTION;
3356
4882
                                                        newCost += c;
3357
 
                                                        if (RoutingDebug.isActive()) costExplanation += " Backward-X-progress=" + c;
 
4883
                                                        if (debuggingWavefront) costExplanation += " Backward-X-progress=" + c;
3358
4884
                                                }
3359
4885
                                        }
3360
4886
                                        if (sogp.isFavorHorVer())
3363
4889
                                                {
3364
4890
                                                        c = (int)Math.round(COSTALTERNATINGMETAL * Math.abs(dx));
3365
4891
                                                        newCost += c;
3366
 
                                                        if (RoutingDebug.isActive()) costExplanation += " Not-alternating-metal=" + c;
 
4892
                                                        if (debuggingWavefront) costExplanation += " Not-alternating-metal=" + c;
3367
4893
                                                }
3368
4894
                                        }
3369
4895
                                }
3373
4899
                                        {
3374
4900
                                                c = COSTWRONGDIRECTION / 2;
3375
4901
                                                newCost += c;
3376
 
                                                if (RoutingDebug.isActive()) costExplanation += " Zero-Y-progress=" + c;
 
4902
                                                if (debuggingWavefront) costExplanation += " Zero-Y-progress=" + c;
3377
4903
                                        } else if ((toY - curY) * dy < 0)
3378
4904
                                        {
3379
4905
                                                if (curX >= toRect.getMinX() && curX <= toRect.getMaxX())
3380
4906
                                                {
3381
4907
                                                        c = 1;
3382
4908
                                                        newCost += c;
3383
 
                                                        if (RoutingDebug.isActive()) costExplanation += " Backward-Y-progress-at-dest-X=" + c;
 
4909
                                                        if (debuggingWavefront) costExplanation += " Backward-Y-progress-at-dest-X=" + c;
3384
4910
                                                } else
3385
4911
                                                {
3386
4912
                                                        c = COSTWRONGDIRECTION;
3387
4913
                                                        newCost += c;
3388
 
                                                        if (RoutingDebug.isActive()) costExplanation += " Backward-Y-progress=" + c;
 
4914
                                                        if (debuggingWavefront) costExplanation += " Backward-Y-progress=" + c;
3389
4915
                                                }
3390
4916
                                        }
3391
4917
                                        if (sogp.isFavorHorVer())
3394
4920
                                                {
3395
4921
                                                        c = (int)Math.round(COSTALTERNATINGMETAL * Math.abs(dy));
3396
4922
                                                        newCost += c;
3397
 
                                                        if (RoutingDebug.isActive()) costExplanation += " Not-alternating-metal=" + c;
 
4923
                                                        if (debuggingWavefront) costExplanation += " Not-alternating-metal=" + c;
3398
4924
                                                }
3399
4925
                                        }
3400
4926
                                }
3404
4930
                                        {
3405
4931
                                                c = COSTLAYERCHANGE;
3406
4932
                                                newCost += c;
3407
 
                                                if (RoutingDebug.isActive()) costExplanation += " Layer-change=" + c;
 
4933
                                                if (debuggingWavefront) costExplanation += " Layer-change=" + c;
3408
4934
                                        } else if ((toZ - curZ) * dz < 0)
3409
4935
                                        {
3410
4936
                                                c = COSTLAYERCHANGE + 1;
3414
4940
//                                              if (distFromGoal > 3) c *= (distFromGoal-3) * COSTLAYERCHANGE;
3415
4941
 
3416
4942
                                                newCost += c;
3417
 
                                                if (RoutingDebug.isActive()) costExplanation += " Layer-change-wrong-direction=" + c;
 
4943
                                                if (debuggingWavefront) costExplanation += " Layer-change-wrong-direction=" + c;
3418
4944
                                        }
3419
4945
                                } else
3420
4946
                                {
3427
4953
                                                if (c > 0)
3428
4954
                                                {
3429
4955
                                                        newCost += c;
3430
 
                                                        if (RoutingDebug.isActive()) costExplanation += " Fragments-track=" + c;
 
4956
                                                        if (debuggingWavefront) costExplanation += " Fragments-track=" + c;
3431
4957
                                                }
3432
4958
                                        }
3433
4959
 
3440
4966
                                                {
3441
4967
                                                        c = COSTTURNING;
3442
4968
                                                        newCost += c;
3443
 
                                                        if (RoutingDebug.isActive()) costExplanation += " Turning=" + c;
 
4969
                                                        if (debuggingWavefront) costExplanation += " Turning=" + c;
3444
4970
                                                }
3445
4971
                                        }
3446
4972
                                }
3448
4974
                                {
3449
4975
                                        c = (int)((COSTLAYERCHANGE * COSTUNFAVORED) * Math.abs(dz) + COSTUNFAVORED * Math.abs(dx + dy));
3450
4976
                                        newCost += c;
3451
 
                                        if (RoutingDebug.isActive()) costExplanation += " Layer-unfavored=" + c;
 
4977
                                        if (debuggingWavefront) costExplanation += " Layer-unfavored=" + c;
3452
4978
                                }
3453
4979
                                if (penaltyOffGridX)
3454
4980
                                {
3455
4981
                                        c = COSTOFFGRID;
3456
4982
                                        newCost += c;
3457
 
                                        if (RoutingDebug.isActive()) costExplanation += " Off-X-grid=" + c;
 
4983
                                        if (debuggingWavefront) costExplanation += " Off-X-grid=" + c;
3458
4984
                                }
3459
4985
                                if (penaltyOffGridY)
3460
4986
                                {
3461
4987
                                        c = COSTOFFGRID;
3462
4988
                                        newCost += c;
3463
 
                                        if (RoutingDebug.isActive()) costExplanation += " Off-Y-grid=" + c;
 
4989
                                        if (debuggingWavefront) costExplanation += " Off-Y-grid=" + c;
3464
4990
                                }
3465
4991
                                svNext.cost = newCost;
3466
4992
 
3469
4995
                                {
3470
4996
                                        if (alreadyThere.getCost() < svNext.getCost())
3471
4997
                                        {
3472
 
                                                if (RoutingDebug.isActive()) completeDebugString(i, ": Already Planned at lower cost (" + alreadyThere.getCost() + ")");
 
4998
                                                if (debuggingWavefront) completeDebugString(i, ": Already planned at lower cost (" + alreadyThere.getCost() + ")");
3473
4999
                                                continue;
3474
5000
                                        }
3475
5001
                                        active.remove(alreadyThere);
3478
5004
                                // add this vertex into the data structures
3479
5005
                                setVertex(nX, nY, nZ, svNext);
3480
5006
                                active.add(svNext);
3481
 
                                if (RoutingDebug.isActive())
 
5007
                                if (debuggingWavefront)
3482
5008
                                {
3483
 
                                        completeDebugString(i, ": To (" + TextUtils.formatDouble(svNext.getX()) + "," + TextUtils.formatDouble(svNext.getY()) +
3484
 
                                                ",M" + (svNext.getZ() + 1) + ")" + costExplanation + "]");
 
5009
                                        completeDebugString(i, ": To (" + TextUtils.formatDistance(svNext.getX()) + "," + TextUtils.formatDistance(svNext.getY()) +
 
5010
                                                "," + svNext.describeMetal() + ")" + costExplanation + "]");
3485
5011
                                }
3486
 
                                if (RoutingDebug.isActive())
 
5012
                                if (debuggingWavefront)
3487
5013
                                        RoutingDebug.saveSVLink(svNext, i);
3488
5014
                        }
3489
 
                        if (RoutingDebug.isActive())
3490
 
                                RoutingDebug.saveSVDetails(svCurrent, debugString);
 
5015
                        if (debuggingWavefront)
 
5016
                                RoutingDebug.saveSVDetails(svCurrent, debugString, false);
 
5017
                        if (destinationSV != null) solution = destinationSV;
3491
5018
                        return destinationSV;
3492
5019
                }
3493
5020
 
 
5021
                /**
 
5022
                 * Method to determine extra geometry needed to ensure minimum area is met
 
5023
                 * @param svCurrent the current SearchVertex that is changing layers (or ending a route).
 
5024
                 * @param curX the X coordinate of the SearchVertex.
 
5025
                 * @param curY the Y coordinate of the SearchVertex.
 
5026
                 * @param curC the mask color of the SearchVertex.
 
5027
                 * @param curZ the metal layer of the SearchVertex.
 
5028
                 * @param mv the contact being placed at this SearchVertex (may be null).
 
5029
                 * @param conWid the width of the contact being placed.
 
5030
                 * @param conHei the height of the contact being placed.
 
5031
                 * @param error set to true if the geometry is needed but cannot be placed.
 
5032
                 * @param message set to an error message which explains the problem.
 
5033
                 * @return a SearchVertexAddon structure (null if no additional geometry is needed or there is an error).
 
5034
                 */
 
5035
                private SearchVertexAddon determineMinimumArea(SearchVertex svCurrent, double curX, double curY, int curC, int curZ, MetalVia mv, double conWid, double conHei, MutableBoolean error, StringBuffer message)
 
5036
                {
 
5037
                        if (MINAREACHECK && minimumArea[curZ] > 0)
 
5038
                        {
 
5039
                                // first compute rectangle in current contact
 
5040
                                Rectangle2D conRect = getExtraGeometryForMinArea(svCurrent, mv, conWid, conHei, curX, curY, curZ);
 
5041
                                if (conRect != null)
 
5042
                                {
 
5043
                                        // see if it is outside of routing bounds
 
5044
                                        if (routingBoundsLimit != null)
 
5045
                                        {
 
5046
                                                if (conRect.getMinX() < routingBoundsLimit.getMinX() || conRect.getMaxX() > routingBoundsLimit.getMaxX() ||
 
5047
                                                        conRect.getMinY() < routingBoundsLimit.getMinY() || conRect.getMaxY() > routingBoundsLimit.getMaxY())
 
5048
                                                {
 
5049
                                                        error.setValue(true);
 
5050
                                                        if (debuggingWavefront)
 
5051
                                                        {
 
5052
                                                                message.append("extra piece of layer " + primaryMetalLayer[curZ].getName() + " for minimum area" +
 
5053
                                                                        " at " + TextUtils.formatDistance(conRect.getMinX()) + "<=X<=" + TextUtils.formatDistance(conRect.getMaxX()) +
 
5054
                                                                        " and " + TextUtils.formatDistance(conRect.getMinY()) + "<=Y<=" + TextUtils.formatDistance(conRect.getMaxY()) +
 
5055
                                                                        " is outside of routing bounds " + TextUtils.formatDistance(routingBoundsLimit.getMinX()) + "<=X<=" + TextUtils.formatDistance(routingBoundsLimit.getMaxX()) +
 
5056
                                                                        " and " + TextUtils.formatDistance(routingBoundsLimit.getMinY()) + "<=Y<=" + TextUtils.formatDistance(routingBoundsLimit.getMaxY()));
 
5057
                                                        }
 
5058
                                                        return null;
 
5059
                                                }
 
5060
                                        }
 
5061
 
 
5062
                                        // see if it creates a design-rule violation
 
5063
                                        double halfWid = conRect.getWidth() / 2;
 
5064
                                        double halfHei = conRect.getHeight() / 2;
 
5065
                                        SOGBound sb = getMetalBlockageAndNotch(curZ, curC, halfWid, halfHei, conRect.getCenterX(), conRect.getCenterY(), svCurrent, true);
 
5066
                                        if (sb != null)
 
5067
                                        {
 
5068
                                                error.setValue(true);
 
5069
                                                if (debuggingWavefront)
 
5070
                                                {
 
5071
                                                        message.append("extra piece of layer " + primaryMetalLayer[curZ].getName() + " for minimum area" +
 
5072
                                                                " at " + TextUtils.formatDistance(conRect.getMinX()) + "<=X<=" + TextUtils.formatDistance(conRect.getMaxX()) +
 
5073
                                                                " and " + TextUtils.formatDistance(conRect.getMinY()) + "<=Y<=" + TextUtils.formatDistance(conRect.getMaxY()) +
 
5074
                                                                " conflicts with " + TextUtils.formatDistance(sb.getBounds().getMinX()) + "<=X<=" + TextUtils.formatDistance(sb.getBounds().getMaxX()) +
 
5075
                                                                " and " + TextUtils.formatDistance(sb.getBounds().getMinY()) + "<=Y<=" + TextUtils.formatDistance(sb.getBounds().getMaxY()));
 
5076
                                                }
 
5077
                                                return null;
 
5078
                                        }
 
5079
 
 
5080
                                        // extra geometry is valid
 
5081
                                        int c = curC;
 
5082
                                        if (c > 0) c--;
 
5083
                                        PrimitiveNode pNp = metalPureLayerNodes[curZ][c];
 
5084
                                        return new SearchVertexAddon(conRect, pNp);
 
5085
                                }
 
5086
                        }
 
5087
                        return null;
 
5088
                }
 
5089
 
 
5090
                /**
 
5091
                 * Method to figure out whether the minimum area has been met for a contact.
 
5092
                 * @param svCurrent the chain of SearchVertex objects leading up to this contact.
 
5093
                 * @param mv the contact that will be placed.
 
5094
                 * @param curX the X coordinate of the contact.
 
5095
                 * @param curY the Y coordinate of the contact.
 
5096
                 * @param curZ the Metal layer being considered for minimum area.
 
5097
                 * @return a Rectangle2D with extra geometry on that layer (if the minimum area has not been met).
 
5098
                 * Returns null if the minimum area has been met.
 
5099
                 */
 
5100
                private Rectangle2D getExtraGeometryForMinArea(SearchVertex svCurrent, MetalVia mv, double wid, double hei, double curX, double curY, int curZ)
 
5101
                {
 
5102
                        // look for SearchVertex with a layer change
 
5103
                        getOptimizedList(svCurrent, optimizedList);
 
5104
                        int lastInd = optimizedList.size() - 1;
 
5105
                        int prevViaMet = 0;
 
5106
                        for (int ind = 1; ind < optimizedList.size(); ind++)
 
5107
                        {
 
5108
                                SearchVertex sv = optimizedList.get(ind);
 
5109
                                SearchVertex lastSv = optimizedList.get(ind - 1);
 
5110
                                if (sv.getZ() != lastSv.getZ())
 
5111
                                {
 
5112
                                        prevViaMet = Math.min(sv.getZ(), lastSv.getZ());
 
5113
                                        lastInd = ind-1;
 
5114
                                        break;
 
5115
                                }
 
5116
                        }
 
5117
                        SearchVertex svLast = optimizedList.get(lastInd);
 
5118
 
 
5119
                        // compute rectangle of metal arc on this layer
 
5120
                        double width = nr.getArcWidth(curZ, curX, curY, svLast.getX(), svLast.getY());
 
5121
                        Point2D head = new Point2D.Double(curX, curY);
 
5122
                        Point2D tail = new Point2D.Double(svLast.getX(), svLast.getY());
 
5123
                        int ang = 0;
 
5124
                        if (head.getX() != tail.getX() || head.getY() != tail.getY())
 
5125
                                ang = GenMath.figureAngle(tail, head);
 
5126
                        Poly poly = Poly.makeEndPointPoly(head.distance(tail), width, ang, head, width / 2, tail,
 
5127
                                width / 2, Poly.Type.FILLED);
 
5128
                        Rectangle2D boundArc = poly.getBounds2D();
 
5129
 
 
5130
                        // compute rectangle in current contact (if there is one)
 
5131
                        Rectangle2D bound;
 
5132
                        if (mv == null) bound = boundArc; else
 
5133
                                bound = getContactGeometry(mv, wid, hei, curX, curY, curZ);
 
5134
 
 
5135
                        // compute rectangle in previous contact (if there is one)
 
5136
                        Rectangle2D boundPrev;
 
5137
                        if (svLast.size == null) boundPrev = boundArc; else
 
5138
                        {
 
5139
                                // previous contact found: compute its bounds
 
5140
                                List<MetalVia> npsPrev = metalVias[prevViaMet].getVias();
 
5141
                                if (nr.is2X(prevViaMet, svLast.getX(), svLast.getY(), svLast.getX(), svLast.getY()) ||
 
5142
                                        (prevViaMet+1 < numMetalLayers && nr.is2X(prevViaMet+1, svLast.getX(), svLast.getY(), svLast.getX(), svLast.getY())))
 
5143
                                {
 
5144
                                        List<MetalVia> nps2X = metalVias2X[prevViaMet].getVias();
 
5145
                                        if (nps2X.size() > 0) npsPrev = nps2X;
 
5146
                                }
 
5147
                                MetalVia mvPrev = npsPrev.get(svLast.getContactNo());
 
5148
                                boundPrev = getContactGeometry(mvPrev, svLast.size.getX(), svLast.size.getY(), svLast.getX(), svLast.getY(), curZ);
 
5149
                        }
 
5150
 
 
5151
                        // if any of the parts is big enough, no need to look further
 
5152
                        if (bound != null && bound.getWidth() * bound.getHeight() >= minimumArea[curZ]) return null;
 
5153
                        if (boundPrev != null && boundPrev.getWidth() * boundPrev.getHeight() >= minimumArea[curZ]) return null;
 
5154
                        if (boundArc != null && boundArc.getWidth() * boundArc.getHeight() >= minimumArea[curZ]) return null;
 
5155
 
 
5156
                        // determine extra geometry needed to satisfy minimum area
 
5157
                        Boolean hor = null;
 
5158
                        if (bound.equals(boundArc) && boundPrev.equals(boundArc))
 
5159
                        {
 
5160
                                if (boundArc.getWidth() > boundArc.getHeight()) hor = Boolean.TRUE; else
 
5161
                                        hor = Boolean.FALSE;
 
5162
                        } else
 
5163
                        {
 
5164
                                if (bound.getMinX() == boundPrev.getMinX() && bound.getMinX() == boundArc.getMinX() &&
 
5165
                                        bound.getMaxX() == boundPrev.getMaxX() && bound.getMaxX() == boundArc.getMaxX()) hor = Boolean.FALSE;
 
5166
                                if (bound.getMinY() == boundPrev.getMinY() && bound.getMinY() == boundArc.getMinY() &&
 
5167
                                        bound.getMaxY() == boundPrev.getMaxY() && bound.getMaxY() == boundArc.getMaxY()) hor = Boolean.TRUE;
 
5168
                        }
 
5169
                        if (hor != null)
 
5170
                        {
 
5171
                                // simple computation if all in a line
 
5172
                                if (!hor.booleanValue())
 
5173
                                {
 
5174
                                        // geometry runs vertically: easy computation of the area
 
5175
                                        double lY = Math.min(bound.getMinY(), Math.min(boundPrev.getMinY(), boundArc.getMinY()));
 
5176
                                        double hY = Math.max(bound.getMaxY(), Math.max(boundPrev.getMaxY(), boundArc.getMaxY()));
 
5177
                                        double area = (hY - lY) * (bound.getMaxX() - bound.getMinX());
 
5178
                                        if (DBMath.isLessThan(area, minimumArea[curZ]))
 
5179
                                        {
 
5180
                                                // compute where extra geometry will go
 
5181
                                                double extraLength = (minimumArea[curZ] - area) / (bound.getMaxX() - bound.getMinX());
 
5182
                                                extraLength = Math.ceil(extraLength / minResolution) * minResolution;
 
5183
                                                if (bound.getCenterY() > boundPrev.getCenterY())
 
5184
                                                        return new Rectangle2D.Double(bound.getMinX(), hY, bound.getWidth(), extraLength);
 
5185
                                                return new Rectangle2D.Double(bound.getMinX(), lY-extraLength, bound.getWidth(), extraLength);
 
5186
                                        }
 
5187
                                } else if (hor.booleanValue())
 
5188
                                {
 
5189
                                        // geometry runs horizontally: easy computation of the area
 
5190
                                        double lX = Math.min(bound.getMinX(), Math.min(boundPrev.getMinX(), boundArc.getMinX()));
 
5191
                                        double hX = Math.max(bound.getMaxX(), Math.max(boundPrev.getMaxX(), boundArc.getMaxX()));
 
5192
                                        double area = (hX - lX) * (bound.getMaxY() - bound.getMinY());
 
5193
                                        if (DBMath.isLessThan(area, minimumArea[curZ]))
 
5194
                                        {
 
5195
                                                // compute where extra geometry will go
 
5196
                                                double extraLength = (minimumArea[curZ] - area) / (bound.getMaxY() - bound.getMinY());
 
5197
                                                extraLength = Math.ceil(extraLength / minResolution) * minResolution;
 
5198
                                                if (bound.getCenterX() > boundPrev.getCenterX())
 
5199
                                                        return new Rectangle2D.Double(hX, bound.getMinY(), extraLength, bound.getHeight());
 
5200
                                                return new Rectangle2D.Double(lX-extraLength, bound.getMinY(), extraLength, bound.getHeight());
 
5201
                                        }
 
5202
                                }
 
5203
                        } else
 
5204
                        {
 
5205
                                // more complex area computation
 
5206
                                PolyMerge pm = new PolyMerge();
 
5207
                                Layer layer = primaryMetalLayer[curZ];
 
5208
                                pm.addPolygon(layer, new PolyBase(bound));
 
5209
                                pm.addPolygon(layer, new PolyBase(boundPrev));
 
5210
                                pm.addPolygon(layer, new PolyBase(boundArc));
 
5211
                                double area = pm.getAreaOfLayer(layer);
 
5212
                                if (DBMath.isLessThan(area, minimumArea[curZ]))
 
5213
                                {
 
5214
                                        if (bound.getCenterX() == boundPrev.getCenterX() && bound.getCenterY() != boundPrev.getCenterY())
 
5215
                                        {
 
5216
                                                // geometry runs vertically
 
5217
                                                double lY = Math.min(bound.getMinY(), Math.min(boundPrev.getMinY(), boundArc.getMinY()));
 
5218
                                                double hY = Math.max(bound.getMaxY(), Math.max(boundPrev.getMaxY(), boundArc.getMaxY()));
 
5219
                                                double extraLength = (minimumArea[curZ] - area) / (bound.getMaxX() - bound.getMinX());
 
5220
                                                extraLength = Math.ceil(extraLength / minResolution) * minResolution;
 
5221
                                                if (bound.getCenterY() > boundPrev.getCenterY())
 
5222
                                                        return new Rectangle2D.Double(bound.getMinX(), hY, bound.getWidth(), extraLength);
 
5223
                                                return new Rectangle2D.Double(bound.getMinX(), lY-extraLength, bound.getWidth(), extraLength);
 
5224
                                        } else if (bound.getCenterX() != boundPrev.getCenterX() && bound.getCenterY() == boundPrev.getCenterY())
 
5225
                                        {
 
5226
                                                // geometry runs horizontally
 
5227
                                                double lX = Math.min(bound.getMinX(), Math.min(boundPrev.getMinX(), boundArc.getMinX()));
 
5228
                                                double hX = Math.max(bound.getMaxX(), Math.max(boundPrev.getMaxX(), boundArc.getMaxX()));
 
5229
                                                double extraLength = (minimumArea[curZ] - area) / (bound.getMaxY() - bound.getMinY());
 
5230
                                                extraLength = Math.ceil(extraLength / minResolution) * minResolution;
 
5231
                                                if (bound.getCenterX() > boundPrev.getCenterX())
 
5232
                                                        return new Rectangle2D.Double(hX, bound.getMinY(), extraLength, bound.getHeight());
 
5233
                                                return new Rectangle2D.Double(lX-extraLength, bound.getMinY(), extraLength, bound.getHeight());
 
5234
                                        } else
 
5235
                                        {
 
5236
                                                // contacts are not in a line, more advanced computation
 
5237
                                                if (bound.getWidth() > bound.getHeight())
 
5238
                                                {
 
5239
                                                        // layer runs horizontally
 
5240
                                                        double extraLength = (minimumArea[curZ] - area) / (bound.getMaxY() - bound.getMinY());
 
5241
                                                        extraLength = Math.ceil(extraLength / minResolution) * minResolution;
 
5242
                                                        if (bound.getCenterX() > boundPrev.getCenterX())
 
5243
                                                                return new Rectangle2D.Double(bound.getMaxX(), bound.getMinY(), extraLength, bound.getHeight());
 
5244
                                                        return new Rectangle2D.Double(bound.getMinX()-extraLength, bound.getMinY(), extraLength, bound.getHeight());
 
5245
                                                } else
 
5246
                                                {
 
5247
                                                        // layer runs vertically
 
5248
                                                        double extraLength = (minimumArea[curZ] - area) / (bound.getMaxX() - bound.getMinX());
 
5249
                                                        extraLength = Math.ceil(extraLength / minResolution) * minResolution;
 
5250
                                                        if (bound.getCenterY() > boundPrev.getCenterY())
 
5251
                                                                return new Rectangle2D.Double(bound.getMinX(), bound.getMaxY(), bound.getWidth(), extraLength);
 
5252
                                                        return new Rectangle2D.Double(bound.getMinX(), bound.getMinY()-extraLength, bound.getWidth(), extraLength);
 
5253
                                                }
 
5254
                                        }
 
5255
                                }
 
5256
                        }
 
5257
                        return null;
 
5258
                }
 
5259
 
 
5260
                /**
 
5261
                 * Method to get the geometry in a given contact and a given metal.
 
5262
                 * @param mv the contact to analyze.
 
5263
                 * @param wid the width of the contact.
 
5264
                 * @param hei the height of the contact.
 
5265
                 * @param curX the X coordinate of the contact.
 
5266
                 * @param curY the Y coordinate of the contact.
 
5267
                 * @param metNum the desired metal in the contact (0-based).
 
5268
                 * @return the rectangle of that metal in the contact.
 
5269
                 */
 
5270
                private Rectangle2D getContactGeometry(MetalVia mv, double wid, double hei, double curX, double curY, int metNum)
 
5271
                {
 
5272
                        PrimitiveNode np = mv.via;
 
5273
                        Orientation orient = Orientation.fromJava(mv.orientation * 10, false, false);
 
5274
                        NodeInst ni = NodeInst.makeDummyInstance(np, ep, EPoint.fromLambda(curX, curY), wid, hei, orient);
 
5275
                        FixpTransform trans = null;
 
5276
                        if (orient != Orientation.IDENT) trans = ni.rotateOut();
 
5277
                        Poly[] polys = np.getTechnology().getShapeOfNode(ni);
 
5278
                        for (int j = 0; j < polys.length; j++)
 
5279
                        {
 
5280
                                Poly poly = polys[j];
 
5281
                                if (poly.getLayer().getFunction().getLevel() != metNum+1) continue;
 
5282
                                if (trans != null) poly.transform(trans);
 
5283
                                return poly.getBounds2D();
 
5284
                        }
 
5285
                        return null;
 
5286
                }
 
5287
 
3494
5288
                private int getNextBucket(SearchVertex svCurrent, double nX, double nY)
3495
5289
                {
3496
5290
                        int start = orderedBase[svCurrent.globalRoutingBucket];
3514
5308
                        }
3515
5309
 
3516
5310
                        // not found at all: an error
3517
 
                        error("ERROR: Could not find next bucket going from ("+TextUtils.formatDouble(svCurrent.xv)+","+
3518
 
                                TextUtils.formatDouble(svCurrent.yv)+") to ("+TextUtils.formatDouble(nX)+","+TextUtils.formatDouble(nY)+
3519
 
                                ") starting at bucket "+orderedBase[svCurrent.globalRoutingBucket]+
3520
 
                                " (really "+svCurrent.globalRoutingBucket+") and going "+globalRoutingDelta);
 
5311
                        error("ERROR: Could not find next bucket going from (" + TextUtils.formatDistance(svCurrent.xv) + "," +
 
5312
                                TextUtils.formatDistance(svCurrent.yv) + ") to (" + TextUtils.formatDistance(nX) + "," + TextUtils.formatDistance(nY) +
 
5313
                                ") starting at bucket " + orderedBase[svCurrent.globalRoutingBucket] +
 
5314
                                " (really " + svCurrent.globalRoutingBucket + ") and going " + globalRoutingDelta);
3521
5315
                        return svCurrent.globalRoutingBucket;
3522
5316
                }
3523
5317
 
3531
5325
                        if (routeName.endsWith("...")) routeName = routeName.substring(0, routeName.length()-3);
3532
5326
                        int parenPos = routeName.lastIndexOf('(');
3533
5327
                        if (parenPos > 0) routeName = routeName.substring(0, parenPos);
3534
 
 
 
5328
                        
3535
5329
                        RouteNode fromRN = new RouteNode(from);
3536
5330
                        RouteNode toRN = new RouteNode(to);
 
5331
                        RouteResolution resolution = nr.batch.resolution;
 
5332
 
 
5333
                        // if endpoints were on forbidden metal layers but quick changes were allowed, insert them now
 
5334
                        if (nr.replaceA != null)
 
5335
                        {
 
5336
                                PrimitiveNode pNp = nr.replaceA.via;
 
5337
                                Orientation orient = Orientation.fromJava(nr.replaceA.orientation * 10, false, false);
 
5338
                                RouteNode newRN = new RouteNode(pNp, SeaOfGatesEngine.this, EPoint.fromLambda(nr.aX, nr.aY),
 
5339
                                        pNp.getDefWidth(ep), pNp.getDefHeight(ep), orient, null, nr);
 
5340
                                resolution.addNode(newRN);
 
5341
                                RouteNode goal = (fromBit == BLOCKAGEENDA ? fromRN : toRN);
 
5342
                                for(RouteArc ra : resolution.arcsToRoute)
 
5343
                                {
 
5344
                                        if (ra.from == goal) ra.from = newRN;
 
5345
                                        if (ra.to == goal) ra.to = newRN;
 
5346
                                }
 
5347
                                ArcProto type = metalArcs[nr.replaceAZ][nr.replaceAC];
 
5348
                                Layer layer = metalLayers[nr.replaceAZ][nr.replaceAC];
 
5349
                                double width = nr.getArcWidth(nr.replaceAZ, nr.aX, nr.aY, nr.aX, nr.aY);
 
5350
                                resolution.addArc(new RouteArc(type, routeName, SeaOfGatesEngine.this, layer, width, newRN, goal, nr));
 
5351
                                if (fromBit == BLOCKAGEENDA) fromRN = newRN; else toRN = newRN;
 
5352
                                routeName = null;
 
5353
                        }
 
5354
                        if (nr.replaceB != null)
 
5355
                        {
 
5356
                                PrimitiveNode pNp = nr.replaceB.via;
 
5357
                                Orientation orient = Orientation.fromJava(nr.replaceB.orientation * 10, false, false);
 
5358
                                RouteNode newRN = new RouteNode(pNp, SeaOfGatesEngine.this, EPoint.fromLambda(nr.bX, nr.bY),
 
5359
                                        pNp.getDefWidth(ep), pNp.getDefHeight(ep), orient, null, nr);
 
5360
                                resolution.addNode(newRN);
 
5361
                                RouteNode goal = (fromBit == BLOCKAGEENDA ? toRN : fromRN);
 
5362
                                for(RouteArc ra : resolution.arcsToRoute)
 
5363
                                {
 
5364
                                        if (ra.from == goal) ra.from = newRN;
 
5365
                                        if (ra.to == goal) ra.to = newRN;
 
5366
                                }
 
5367
                                ArcProto type = metalArcs[nr.replaceBZ][nr.replaceBC];
 
5368
                                Layer layer = metalLayers[nr.replaceBZ][nr.replaceBC];
 
5369
                                double width = nr.getArcWidth(nr.replaceBZ, nr.bX, nr.bY, nr.bX, nr.bY);
 
5370
                                resolution.addArc(new RouteArc(type, routeName, SeaOfGatesEngine.this, layer, width, newRN, goal, nr));
 
5371
                                if (fromBit == BLOCKAGEENDA) toRN = newRN; else fromRN = newRN;
 
5372
                                routeName = null;
 
5373
                        }
 
5374
 
3537
5375
                        RouteNode lastRN = toRN;
3538
5376
                        PolyBase toPoly = to.getPoly();
3539
 
                        double minWidth = nr.minWidth;
3540
 
                        RouteResolution resolution = nr.batch.resolution;
3541
5377
                        if (!DBMath.pointInRect(EPoint.fromLambda(toX, toY), toRect))
3542
5378
                        {
3543
5379
                                // end of route is off-grid: adjust it
3545
5381
                                {
3546
5382
                                        SearchVertex v1 = vertices.get(0);
3547
5383
                                        SearchVertex v2 = vertices.get(1);
3548
 
                                        ArcProto type = metalArcs[toZ];
3549
 
                                        Layer layer = metalLayers[toZ];
3550
 
                                        double width = nr.getArcWidth(toZ);
3551
 
                                        PrimitiveNode np = metalArcs[toZ].findPinProto();
 
5384
                                        int tc = toC;
 
5385
                                        if (tc > 0) tc--;
 
5386
                                        ArcProto type = metalArcs[toZ][tc];
 
5387
                                        Layer layer = metalLayers[toZ][tc];
 
5388
                                        double width = nr.getArcWidth(toZ, toX, toY, toX, toY);
 
5389
                                        PrimitiveNode np = metalArcs[toZ][tc].findPinProto();
3552
5390
                                        if (v1.getX() == v2.getX())
3553
5391
                                        {
3554
5392
                                                // first line is vertical: run a horizontal bit
3572
5410
                                        }
3573
5411
                                }
3574
5412
                        }
 
5413
 
3575
5414
                        for (int i = 0; i < vertices.size(); i++)
3576
5415
                        {
3577
5416
                                SearchVertex sv = vertices.get(i);
 
5417
                                SearchVertexAddon sva = sv.getMoreGeometry();
 
5418
                                if (sva != null)
 
5419
                                {
 
5420
                                        Rectangle2D addedGeometry = sva.getGeometry();
 
5421
                                        PrimitiveNode pNp = sva.getPureLayerNode();
 
5422
                                        RouteNode rn = new RouteNode(pNp, SeaOfGatesEngine.this, EPoint.fromLambda(addedGeometry.getCenterX(), addedGeometry.getCenterY()),
 
5423
                                                addedGeometry.getWidth(), addedGeometry.getHeight(), Orientation.IDENT, null, nr);
 
5424
                                        resolution.addNode(rn);
 
5425
                                }
 
5426
                                
3578
5427
                                boolean madeContacts = false;
3579
5428
                                while (i < vertices.size() - 1)
3580
5429
                                {
3581
5430
                                        SearchVertex svNext = vertices.get(i + 1);
3582
5431
                                        if (sv.getX() != svNext.getX() || sv.getY() != svNext.getY() || sv.getZ() == svNext.getZ()) break;
3583
 
                                        List<MetalVia> nps = metalVias[Math.min(sv.getZ(), svNext.getZ())].getVias();
 
5432
                                        int metNum = Math.min(sv.getZ(), svNext.getZ());
 
5433
                                        List<MetalVia> nps = metalVias[metNum].getVias();
 
5434
                                        if (nr.is2X(metNum, sv.getX(), sv.getY(), sv.getX(), sv.getY()) ||
 
5435
                                                (metNum+1 < numMetalLayers && nr.is2X(metNum+1, sv.getX(), sv.getY(), sv.getX(), sv.getY())))
 
5436
                                        {
 
5437
                                                List<MetalVia> nps2X = metalVias2X[metNum].getVias();
 
5438
                                                if (nps2X.size() > 0) nps = nps2X;
 
5439
                                        }
3584
5440
                                        int whichContact = sv.getContactNo();
3585
5441
                                        MetalVia mv = nps.get(whichContact);
3586
5442
                                        PrimitiveNode np = mv.via;
3587
5443
                                        Orientation orient = Orientation.fromJava(mv.orientation * 10, false, false);
3588
 
                                        SizeOffset so = np.getProtoSizeOffset();
3589
 
                                        double xOffset = so.getLowXOffset() + so.getHighXOffset();
3590
 
                                        double yOffset = so.getLowYOffset() + so.getHighYOffset();
3591
 
                                        double wid = Math.max(np.getDefWidth(ep) - xOffset, minWidth) + xOffset;
3592
 
                                        double hei = Math.max(np.getDefHeight(ep) - yOffset, minWidth) + yOffset;
3593
5444
                                        Point2D size = sv.getSize();
3594
 
                                        wid = size.getX();   hei = size.getY();
3595
 
                                        ArcProto type = metalArcs[sv.getZ()];
3596
 
                                        Layer layer = metalLayers[sv.getZ()];
3597
 
                                        double width = nr.getArcWidth(sv.getZ());
3598
 
                                        RouteNode rn = new RouteNode(np, SeaOfGatesEngine.this, EPoint.fromLambda(sv.getX(), sv.getY()), wid, hei, orient, null, nr);
 
5445
                                        double conWid = size.getX();
 
5446
                                        double conHei = size.getY();
 
5447
                                        double otherX = sv.getX(), otherY = sv.getY();
 
5448
                                        if (i > 0)
 
5449
                                        {
 
5450
                                                otherX = vertices.get(i-1).getX();
 
5451
                                                otherY = vertices.get(i-1).getY();
 
5452
                                        }
 
5453
                                        double width = nr.getArcWidth(sv.getZ(), sv.getX(), sv.getY(), otherX, otherY);
 
5454
 
 
5455
                                        // shrink size if metals are narrower (tapered)
 
5456
                                        double fartherX = sv.getX(), fartherY = sv.getY();
 
5457
                                        for(int j=i+1; j<vertices.size(); j++)
 
5458
                                        {
 
5459
                                                SearchVertex svFarther = vertices.get(j);
 
5460
                                                fartherX = svFarther.getX();
 
5461
                                                fartherY = svFarther.getY();
 
5462
                                                if (svFarther.getZ() != svNext.getZ()) break;
 
5463
                                        }
 
5464
                                        double widthNext = nr.getArcWidth(svNext.getZ(), sv.getX(), sv.getY(), fartherX, fartherY);
 
5465
                                        if (mv.horMetal == sv.getZ())
 
5466
                                        {
 
5467
                                                double arcWid = width + mv.horMetalInset;
 
5468
                                                if (arcWid < conHei) conHei = arcWid;
 
5469
                                        } else if (mv.horMetal == svNext.getZ())
 
5470
                                        {
 
5471
                                                double arcWid = widthNext + mv.horMetalInset;
 
5472
                                                if (arcWid < conHei) conHei = arcWid;
 
5473
                                        }
 
5474
                                        if (mv.verMetal == sv.getZ())
 
5475
                                        {
 
5476
                                                double arcWid = width + mv.verMetalInset;
 
5477
                                                if (arcWid < conWid) conWid = arcWid;
 
5478
                                        } else if (mv.verMetal == svNext.getZ())
 
5479
                                        {
 
5480
                                                double arcWid = widthNext + mv.verMetalInset;
 
5481
                                                if (arcWid < conWid) conWid = arcWid;
 
5482
                                        }
 
5483
 
 
5484
                                        int sCol = sv.getC();
 
5485
                                        if (sCol > 0) sCol--;
 
5486
                                        ArcProto type = metalArcs[sv.getZ()][sCol];
 
5487
                                        Layer layer = metalLayers[sv.getZ()][sCol];
 
5488
                                        RouteNode rn = new RouteNode(np, SeaOfGatesEngine.this, EPoint.fromLambda(sv.getX(), sv.getY()), conWid, conHei, orient, null, nr);
3599
5489
                                        resolution.addNode(rn);
3600
5490
                                        RouteArc ra = new RouteArc(type, routeName, SeaOfGatesEngine.this, layer, width, lastRN, rn, nr);
3601
5491
                                        routeName = null;
3607
5497
                                }
3608
5498
                                if (madeContacts && i != vertices.size() - 1) continue;
3609
5499
 
3610
 
                                PrimitiveNode np = metalArcs[sv.getZ()].findPinProto();
 
5500
                                int sCol = sv.getC();
 
5501
                                if (sCol > 0) sCol--;
 
5502
                                PrimitiveNode np = metalArcs[sv.getZ()][sCol].findPinProto();
3611
5503
                                RouteNode piRN;
3612
5504
                                if (i == vertices.size() - 1)
3613
5505
                                {
3617
5509
                                                // end of route is off-grid: adjust it
3618
5510
                                                if (vertices.size() >= 2)
3619
5511
                                                {
 
5512
                                                        int fc = fromC;
 
5513
                                                        if (fc > 0) fc--;
3620
5514
                                                        SearchVertex v1 = vertices.get(vertices.size() - 2);
3621
5515
                                                        SearchVertex v2 = vertices.get(vertices.size() - 1);
3622
 
                                                        ArcProto type = metalArcs[fromZ];
3623
 
                                                        Layer layer = metalLayers[fromZ];
3624
 
                                                        double width = nr.getArcWidth(fromZ);
 
5516
                                                        ArcProto type = metalArcs[fromZ][fc];
 
5517
                                                        Layer layer = metalLayers[fromZ][fc];
 
5518
                                                        double width = nr.getArcWidth(fromZ, fromX, fromY, fromX, fromY);
3625
5519
                                                        if (v1.getX() == v2.getX())
3626
5520
                                                        {
3627
5521
                                                                // last line is vertical: run a horizontal bit
3628
 
                                                                PrimitiveNode pNp = metalArcs[fromZ].findPinProto();
 
5522
                                                                PrimitiveNode pNp = metalArcs[fromZ][fc].findPinProto();
3629
5523
                                                                piRN = new RouteNode(pNp, SeaOfGatesEngine.this, EPoint.fromLambda(v1.getX(), fromY),
3630
5524
                                                                        np.getDefWidth(ep), np.getDefHeight(ep), Orientation.IDENT, null, nr);
3631
5525
                                                                resolution.addNode(piRN);
3635
5529
                                                        } else if (v1.getY() == v2.getY())
3636
5530
                                                        {
3637
5531
                                                                // last line is horizontal: run a vertical bit
3638
 
                                                                PrimitiveNode pNp = metalArcs[fromZ].findPinProto();
 
5532
                                                                PrimitiveNode pNp = metalArcs[fromZ][fc].findPinProto();
3639
5533
                                                                piRN = new RouteNode(pNp, SeaOfGatesEngine.this, EPoint.fromLambda(fromX, v1.getY()),
3640
5534
                                                                        np.getDefWidth(ep), np.getDefHeight(ep), Orientation.IDENT, null, nr);
3641
5535
                                                                resolution.addNode(piRN);
3655
5549
                                }
3656
5550
                                if (lastRN != null)
3657
5551
                                {
3658
 
                                        ArcProto type = metalArcs[sv.getZ()];
3659
 
                                        Layer layer = metalLayers[sv.getZ()];
3660
 
                                        double width = nr.getArcWidth(sv.getZ());
 
5552
                                        ArcProto type = metalArcs[sv.getZ()][sCol];
 
5553
                                        Layer layer = metalLayers[sv.getZ()][sCol];
 
5554
                                        Layer primaryLayer = primaryMetalLayer[sv.getZ()];
 
5555
                                        double width = nr.getArcWidth(sv.getZ(), sv.getX(), sv.getY(), sv.getX(), sv.getY());
3661
5556
                                        if (ANYPOINTONDESTINATION && i == 0)
3662
5557
                                        {
3663
5558
                                                if (!DBMath.rectsIntersect(lastRN.rect, piRN.rect))
3670
5565
                                                        double lY = Math.min(fY, tY) - width/2;
3671
5566
                                                        double hY = Math.max(fY, tY) + width/2;
3672
5567
                                                        Rectangle2D searchArea = new Rectangle2D.Double(lX, lY, hX-lX, hY-lY);
3673
 
                                                        BlockageTree bTree = rTrees.getMetalTree(layer);
 
5568
                                                        BlockageTree bTree = rTrees.getMetalTree(primaryLayer);
3674
5569
                                                        boolean covered = false;
3675
5570
                                                        bTree.lock();
3676
5571
                                                        try {
3696
5591
                                                                if (fX == tX || fY == tY)
3697
5592
                                                                {
3698
5593
                                                                        // try running a single arc
3699
 
                                                                        SOGBound errSV = getMetalBlockageAndNotch(sv.getZ(), (hX-lX)/2, (hY-lY)/2, (hX+lX)/2, (hY+lY)/2, null);
 
5594
                                                                        SOGBound errSV = getMetalBlockageAndNotch(sv.getZ(), sv.getC(), (hX-lX)/2, (hY-lY)/2, (hX+lX)/2, (hY+lY)/2, null, false);
3700
5595
                                                                        if (errSV == null) geomOK = true;
3701
5596
                                                                } else
3702
5597
                                                                {
3716
5611
                                                                        double bend2bLX = hX - width, bend2bHX = hX;
3717
5612
                                                                        double bend2bLY = lY, bend2bHY = hY;
3718
5613
 
3719
 
                                                                        SOGBound errSVa = getMetalBlockageAndNotch(sv.getZ(), (bend1aHX-bend1aLX)/2, (bend1aHY-bend1aLY)/2, (bend1aHX+bend1aLX)/2, (bend1aHY+bend1aLY)/2, null);
3720
 
                                                                        SOGBound errSVb = getMetalBlockageAndNotch(sv.getZ(), (bend1bHX-bend1bLX)/2, (bend1bHY-bend1bLY)/2, (bend1bHX+bend1bLX)/2, (bend1bHY+bend1bLY)/2, null);
 
5614
                                                                        SOGBound errSVa = getMetalBlockageAndNotch(sv.getZ(), sv.getC(), (bend1aHX-bend1aLX)/2, (bend1aHY-bend1aLY)/2, (bend1aHX+bend1aLX)/2, (bend1aHY+bend1aLY)/2, null, false);
 
5615
                                                                        SOGBound errSVb = getMetalBlockageAndNotch(sv.getZ(), sv.getC(), (bend1bHX-bend1bLX)/2, (bend1bHY-bend1bLY)/2, (bend1bHX+bend1bLX)/2, (bend1bHY+bend1bLY)/2, null, false);
3721
5616
                                                                        if (errSVa == null && errSVb == null)
3722
5617
                                                                        {
3723
5618
                                                                                RouteNode bend1RN = new RouteNode(np, SeaOfGatesEngine.this, EPoint.fromLambda(bend1X, bend1Y),
3731
5626
                                                                                System.out.println("AVOIDED UNIVERSAL ARC BECAUSE BEND 1 WORKS");
3732
5627
                                                                        } else
3733
5628
                                                                        {
3734
 
                                                                                errSVa = getMetalBlockageAndNotch(sv.getZ(), (bend2aHX-bend2aLX)/2, (bend2aHY-bend2aLY)/2, (bend2aHX+bend2aLX)/2, (bend2aHY+bend2aLY)/2, null);
3735
 
                                                                                errSVb = getMetalBlockageAndNotch(sv.getZ(), (bend2bHX-bend2bLX)/2, (bend2bHY-bend2bLY)/2, (bend2bHX+bend2bLX)/2, (bend2bHY+bend2bLY)/2, null);
 
5629
                                                                                errSVa = getMetalBlockageAndNotch(sv.getZ(), sv.getC(), (bend2aHX-bend2aLX)/2, (bend2aHY-bend2aLY)/2, (bend2aHX+bend2aLX)/2, (bend2aHY+bend2aLY)/2, null, false);
 
5630
                                                                                errSVb = getMetalBlockageAndNotch(sv.getZ(), sv.getC(), (bend2bHX-bend2bLX)/2, (bend2bHY-bend2bLY)/2, (bend2bHX+bend2bLX)/2, (bend2bHY+bend2bLY)/2, null, false);
3736
5631
                                                                                if (errSVa == null && errSVb == null)
3737
5632
                                                                                {
3738
5633
                                                                                        RouteNode bend2RN = new RouteNode(np, SeaOfGatesEngine.this, EPoint.fromLambda(bend2X, bend2Y),
3749
5644
                                                                }
3750
5645
                                                                if (!geomOK)
3751
5646
                                                                {
3752
 
System.out.println("WARNING: Placing Universal are on route from port "+from.getPortProto().getName()+" of node "+describe(from.getNodeInst())+
3753
 
        " AT ("+fromX+","+fromY+",M"+(fromZ+1)+") to port "+to.getPortProto().getName()+" of node "+describe(to.getNodeInst())+
3754
 
        " AT ("+toX+","+toY+",M"+(toZ+1)+")");
3755
 
//for(SearchVertex v : vertices)
3756
 
//      System.out.println("   SEARCHVERTEX ("+v.xv+","+v.yv+",M"+(v.getZ()+1)+")");
3757
 
 
 
5647
System.out.println("WARNING: Placing Universal arc on route from port "+from.getPortProto().getName()+" of node "+describe(from.getNodeInst())+
 
5648
        " AT ("+TextUtils.formatDistance(fromX)+","+TextUtils.formatDistance(fromY)+","+describeMetal(fromZ,fromC)+") to port "+to.getPortProto().getName()+" of node "+describe(to.getNodeInst())+
 
5649
        " AT ("+TextUtils.formatDistance(toX)+","+TextUtils.formatDistance(toY)+","+describeMetal(toZ,toC)+")");
3758
5650
                                                                        type = Generic.tech().universal_arc;
3759
5651
                                                                        layer = null;
3760
5652
                                                                        width = 0;
3794
5686
                        }
3795
5687
                }
3796
5688
 
3797
 
                private double getJumpSize(SearchVertex sv, double curX, double curY, int curZ, double dx, double dy, MutableBoolean foundDestination)
 
5689
                /**
 
5690
                 * Method to find the X position on a horizontal line that is a given design-rule distance from a blockage point.
 
5691
                 * @param xPos an X coordinate on the horizontal line.
 
5692
                 * @param yPos the Y coordinate of the horizontal line.
 
5693
                 * @param drDist the given design-rule distance.
 
5694
                 * @param xBlock the X coordinate of the blockage point.
 
5695
                 * @param yBlock the Y coordinate of the blockage point.
 
5696
                 * @return the new X coordinate along the horizontal line that is the distance from the point.
 
5697
                 * Returns null if there is no intersection.
 
5698
                 */
 
5699
                private Double getHorizontalBlockage(double xPos, double yPos, double drDist, double xBlock, double yBlock)
 
5700
                {
 
5701
                        double dY = yBlock - yPos;
 
5702
                        if (dY >= drDist) return null;
 
5703
                        double dX = Math.sqrt(drDist*drDist - dY*dY);
 
5704
                        if (xPos > xBlock) return new Double(xBlock + dX);
 
5705
                        return new Double(xBlock - dX);
 
5706
                }
 
5707
 
 
5708
                /**
 
5709
                 * Method to find the X position on a vertical line that is a given design-rule distance from a blockage point.
 
5710
                 * @param xPos the X coordinate on the vertical line.
 
5711
                 * @param yPos a Y coordinate of the vertical line.
 
5712
                 * @param drDist the given design-rule distance.
 
5713
                 * @param xBlock the X coordinate of the blockage point.
 
5714
                 * @param yBlock the Y coordinate of the blockage point.
 
5715
                 * @return the new Y coordinate along the vertical line that is the distance from the point.
 
5716
                 * Returns null if there is no intersection.
 
5717
                 */
 
5718
                private Double getVerticalBlockage(double xPos, double yPos, double drDist, double xBlock, double yBlock)
 
5719
                {
 
5720
                        double dX = xBlock - xPos;
 
5721
                        if (dX >= drDist) return null;
 
5722
                        double dY = Math.sqrt(drDist*drDist - dX*dX);
 
5723
                        if (yPos > yBlock) return new Double(yBlock + dY);
 
5724
                        return new Double(yBlock - dY);
 
5725
                }
 
5726
 
 
5727
                private double getJumpSize(SearchVertex sv, double curX, double curY, int curZ, double dx, double dy,
 
5728
                        StringBuffer explanation)
3798
5729
                {
3799
5730
                        Rectangle2D jumpBound = nr.jumpBound;
3800
 
                        double width = nr.getArcWidth(curZ);
 
5731
                        double width = nr.getArcWidth(curZ, curX, curY, curX+dx, curY+dy);
 
5732
                        double halfWidth = width / 2;
3801
5733
                        double[] fromSurround = nr.getSpacingRule(curZ, width, 50);
3802
 
                        double metalSpacingX = width / 2 + fromSurround[0];
3803
 
                        double metalSpacingY = width / 2 + fromSurround[1];
3804
 
                        double lX = curX - metalSpacingX, hX = curX + metalSpacingX;
3805
 
                        double lY = curY - metalSpacingY, hY = curY + metalSpacingY;
3806
 
                        if (dx > 0) hX = jumpBound.getMaxX() + metalSpacingX; else
3807
 
                                if (dx < 0) lX = jumpBound.getMinX() - metalSpacingX; else
3808
 
                                        if (dy > 0) hY = jumpBound.getMaxY() + metalSpacingY; else
3809
 
                                                if (dy < 0) lY = jumpBound.getMinY() - metalSpacingY;
3810
 
 
3811
 
                        BlockageTree bTree = rTrees.getMetalTree(metalLayers[curZ]);
 
5734
                        double lX = curX - halfWidth, hX = curX + halfWidth;
 
5735
                        double lY = curY - halfWidth, hY = curY + halfWidth;
 
5736
                        if (dx > 0) hX = jumpBound.getMaxX() + halfWidth; else
 
5737
                                if (dx < 0) lX = jumpBound.getMinX() - halfWidth; else
 
5738
                                        if (dy > 0) hY = jumpBound.getMaxY() + halfWidth; else
 
5739
                                                if (dy < 0) lY = jumpBound.getMinY() - halfWidth;
 
5740
                        BlockageTree bTree = rTrees.getMetalTree(primaryMetalLayer[curZ]);
 
5741
                        Rectangle2D topX = null, botX = null, topY = null, botY = null;
3812
5742
                        bTree.lock();
3813
5743
                        try {
3814
5744
                                if (!bTree.isEmpty())
3815
5745
                                {
3816
5746
                                        // see if there is anything in that area
3817
 
                                        boolean hitDestination = false;
3818
 
                                        Rectangle2D searchArea = new Rectangle2D.Double(lX, lY, hX - lX, hY - lY);
3819
 
                                        for (Iterator<SOGBound> sea = bTree.search(searchArea); sea.hasNext();)
 
5747
                                        double lXSearch = lX - fromSurround[0], hXSearch = hX + fromSurround[0];
 
5748
                                        double lYSearch = lY - fromSurround[1], hYSearch = hY + fromSurround[1];
 
5749
                                        Rectangle2D searchArea = new Rectangle2D.Double(lXSearch, lYSearch, hXSearch - lXSearch, hYSearch - lYSearch);
 
5750
                                        for (Iterator<SOGBound> sea = bTree.search(searchArea); sea.hasNext(); )
3820
5751
                                        {
3821
5752
                                                SOGBound sBound = sea.next();
3822
5753
                                                Rectangle2D bound = sBound.getBounds();
3823
 
                                                if (sBound.isSameBasicNet(nr.netID))
3824
 
                                                {
3825
 
                                                        if (foundDestination != null && sBound.hasEndBit(toBit))
3826
 
                                                        {
3827
 
                                                                if (dx > 0 && bound.getCenterX() + metalSpacingX < hX) { hX = bound.getCenterX() + metalSpacingX;  hitDestination = true; }
3828
 
                                                                if (dx < 0 && bound.getCenterX() - metalSpacingX > lX) { lX = bound.getCenterX() - metalSpacingX;  hitDestination = true; }
3829
 
                                                                if (dy > 0 && bound.getCenterY() + metalSpacingY < hY) { hY = bound.getCenterY() + metalSpacingY;  hitDestination = true; }
3830
 
                                                                if (dy < 0 && bound.getCenterY() - metalSpacingY > lY) { lY = bound.getCenterY() - metalSpacingY;  hitDestination = true; }
3831
 
                                                        }
3832
 
                                                        continue;
3833
 
                                                }
3834
 
                                                if (bound.getMinX() >= hX || bound.getMaxX() <= lX || bound.getMinY() >= hY || bound.getMaxY() <= lY)
3835
 
                                                        continue;
3836
 
                                                if (dx > 0 && bound.getMinX() < hX) { hX = bound.getMinX();  hitDestination = false; }
3837
 
                                                if (dx < 0 && bound.getMaxX() > lX) { lX = bound.getMaxX();  hitDestination = false; }
3838
 
                                                if (dy > 0 && bound.getMinY() < hY) { hY = bound.getMinY();  hitDestination = false; }
3839
 
                                                if (dy < 0 && bound.getMaxY() > lY) { lY = bound.getMaxY();  hitDestination = false; }
 
5754
                                                if (sBound.isSameBasicNet(nr.netID)) continue;
 
5755
 
 
5756
                                                // handle diagonal spacing
 
5757
                                                if (lX <= bound.getMaxX() && hX >= bound.getMinX())
 
5758
                                                {
 
5759
                                                        if (lY <= bound.getMaxY() && hY >= bound.getMinY())
 
5760
                                                        {
 
5761
                                                                // rectangles touch or overlap
 
5762
                                                                if (dx > 0 && bound.getMinX()-fromSurround[0] < hX) { hX = bound.getMinX()-fromSurround[0];  topX = bound; }
 
5763
                                                                if (dx < 0 && bound.getMaxX()+fromSurround[0] > lX) { lX = bound.getMaxX()+fromSurround[0];  botX = bound; }
 
5764
                                                                if (dy > 0 && bound.getMinY()-fromSurround[1] < hY) { hY = bound.getMinY()-fromSurround[1];  topY = bound; }
 
5765
                                                                if (dy < 0 && bound.getMaxY()+fromSurround[1] > lY) { lY = bound.getMaxY()+fromSurround[1];  botY = bound; }
 
5766
                                                                continue;
 
5767
                                                        }
 
5768
 
 
5769
                                                        // rectangles are one above the other
 
5770
                                                        double diff;
 
5771
                                                        if ((lY+hY)/2 > (bound.getMinY()+bound.getMaxY())/2)
 
5772
                                                                diff = lY - bound.getMaxY(); else
 
5773
                                                                        diff = bound.getMinY() - hY;
 
5774
                                                        if (DBMath.isGreaterThanOrEqualTo(diff, fromSurround[1])) continue;
 
5775
                                                } else
 
5776
                                                {
 
5777
                                                        if (lY <= bound.getMaxY() && hY >= bound.getMinY())
 
5778
                                                        {
 
5779
                                                                // rectangles are side-by-side
 
5780
                                                                double diff;
 
5781
                                                                if ((lX+hX)/2 > (bound.getMinX()+bound.getMaxX())/2)
 
5782
                                                                        diff = lX - bound.getMaxX(); else
 
5783
                                                                                diff = bound.getMinX() - hX;
 
5784
                                                                if (DBMath.isGreaterThanOrEqualTo(diff, fromSurround[0])) continue;
 
5785
                                                        } else
 
5786
                                                        {
 
5787
                                                                // diagonal offset, compute Euclidean distance to corners
 
5788
                                                                double cut2CornerX, cut2CornerY, cut1CornerX, cut1CornerY;
 
5789
                                                                if ((bound.getMinX()+bound.getMaxX())/2 < (lX+hX)/2)
 
5790
                                                                {
 
5791
                                                                        cut2CornerX = bound.getMaxX();
 
5792
                                                                        cut1CornerX = lX;
 
5793
                                                                } else
 
5794
                                                                {
 
5795
                                                                        cut2CornerX = bound.getMinX();
 
5796
                                                                        cut1CornerX = hX;
 
5797
                                                                }
 
5798
                                                                if ((bound.getMinY()+bound.getMaxY())/2 < (lY+hY)/2)
 
5799
                                                                {
 
5800
                                                                        cut2CornerY = bound.getMaxY();
 
5801
                                                                        cut1CornerY = lY;
 
5802
                                                                } else
 
5803
                                                                {
 
5804
                                                                        cut2CornerY = bound.getMinY();
 
5805
                                                                        cut1CornerY = hY;
 
5806
                                                                }
 
5807
                                                                double dX = Math.abs(cut2CornerX - cut1CornerX);
 
5808
                                                                double dY = Math.abs(cut2CornerY - cut1CornerY);
 
5809
                                                                if (DBMath.isGreaterThanOrEqualTo(dX, fromSurround[0])) continue;
 
5810
                                                                if (DBMath.isGreaterThanOrEqualTo(dY, fromSurround[1])) continue;
 
5811
                                                                double diff = Math.sqrt(dX*dX + dY*dY);
 
5812
                                                                if (DBMath.isGreaterThanOrEqualTo(diff, Math.max(fromSurround[0], fromSurround[1]))) continue;
 
5813
                                                        }
 
5814
                                                }
 
5815
 
 
5816
                                                // determine diagonal limit to the jump
 
5817
                                                if (dx != 0)
 
5818
                                                {
 
5819
                                                        // horizontal line
 
5820
                                                        double drDist = Math.max(fromSurround[0], fromSurround[1]);
 
5821
                                                        double xBlock = bound.getCenterX() < curX ? bound.getMaxX() : bound.getMinX();
 
5822
                                                        double yBlock = bound.getCenterY() < curY ? bound.getMaxY() : bound.getMinY();
 
5823
                                                        Double lYintX = getHorizontalBlockage(curX, lY, drDist, xBlock, yBlock);
 
5824
                                                        Double hYintX = getHorizontalBlockage(curX, hY, drDist, xBlock, yBlock);
 
5825
                                                        if (dx < 0)
 
5826
                                                        {
 
5827
                                                                // moving left
 
5828
                                                                if (lYintX != null && lYintX.doubleValue() > lX && lYintX.doubleValue() <= curX) { lX = lYintX.doubleValue();  botX = bound; }
 
5829
                                                                if (hYintX != null && hYintX.doubleValue() > lX && hYintX.doubleValue() <= curX) { lX = hYintX.doubleValue();  botX = bound; }
 
5830
                                                        } else
 
5831
                                                        {
 
5832
                                                                // moving right
 
5833
                                                                if (lYintX != null && lYintX.doubleValue() < hX && lYintX.doubleValue() >= curX) { hX = lYintX.doubleValue();  topX = bound; }
 
5834
                                                                if (hYintX != null && hYintX.doubleValue() < hX && hYintX.doubleValue() >= curX) { hX = hYintX.doubleValue();  topX = bound; }
 
5835
                                                        }
 
5836
                                                } else
 
5837
                                                {
 
5838
                                                        // vertical line
 
5839
                                                        double drDist = Math.max(fromSurround[0], fromSurround[1]);
 
5840
                                                        double xBlock = bound.getCenterX() < curX ? bound.getMaxX() : bound.getMinX();
 
5841
                                                        double yBlock = bound.getCenterY() < curY ? bound.getMaxY() : bound.getMinY();
 
5842
                                                        Double lXintY = getVerticalBlockage(lX, curY, drDist, xBlock, yBlock);
 
5843
                                                        Double hXintY = getVerticalBlockage(hX, curY, drDist, xBlock, yBlock);
 
5844
                                                        if (dy < 0)
 
5845
                                                        {
 
5846
                                                                // moving down
 
5847
                                                                if (lXintY != null && lXintY.doubleValue() > lY && lXintY.doubleValue() <= curY) { lY = lXintY.doubleValue();  botY = bound; }
 
5848
                                                                if (hXintY != null && hXintY.doubleValue() > lY && hXintY.doubleValue() <= curY) { lY = hXintY.doubleValue();  botY = bound; }
 
5849
                                                        } else
 
5850
                                                        {
 
5851
                                                                // moving up
 
5852
                                                                if (lXintY != null && lXintY.doubleValue() < hY && lXintY.doubleValue() >= curY) { hY = lXintY.doubleValue();  topY = bound; }
 
5853
                                                                if (hXintY != null && hXintY.doubleValue() < hY && hXintY.doubleValue() >= curY) { hY = hXintY.doubleValue();  topY = bound; }
 
5854
                                                        }
 
5855
                                                }
3840
5856
                                        }
3841
 
                                        if (foundDestination != null) foundDestination.setValue(hitDestination);
3842
5857
                                }
3843
5858
                        } finally {
3844
5859
                                bTree.unlock();
3845
5860
                        }
3846
5861
                        if (dx > 0)
3847
5862
                        {
3848
 
                                dx = nr.downToGrain(hX - metalSpacingX) - curX;
 
5863
                                dx = nr.downToGrain(hX - halfWidth) - curX;
 
5864
                                if (fromTaperLen >= 0 && !sv.isOffInitialSegment() && dx > fromTaperLen) dx = fromTaperLen;
 
5865
                                if (curZ == toZ && curY == toY && curX < toX && curX+dx > toX) dx = toX - curX;
3849
5866
                                if (curX + dx > toX && curY >= toRect.getMinY() && curY <= toRect.getMaxY() && curZ == toZ) dx = toX - curX; else
3850
5867
                                {
3851
5868
                                        if (!inDestGrid(toRectGridded, curX+dx, curY))
3852
 
                                                dx = nr.getLowerXGrid(curZ, curX+dx) - curX;
 
5869
                                                dx = nr.getLowerXGrid(curZ, curX+dx).getCoordinate() - curX;
3853
5870
                                        if (globalRoutingDelta != 0)
3854
5871
                                        {
3855
5872
                                                Rectangle2D limit = orderedBuckets[sv.globalRoutingBucket];
3861
5878
                                                        // if moved into a new bucket, center it
3862
5879
                                                        if (curX >= originalBucket.getMinX() && curX >= originalBucket.getMaxX() && curX + dx > originalBucket.getMaxX())
3863
5880
                                                                dx -= originalBucket.getWidth()/2;
3864
 
                                                        dx = nr.getClosestXGrid(curZ, curX+dx) - curX;
 
5881
                                                        dx = nr.getClosestXGrid(curZ, curX+dx).getCoordinate() - curX;
3865
5882
                                                }
3866
5883
                                        }
3867
5884
                                        if (curX + dx > toRect.getMaxX() || curX + dx < toRect.getMinX()) dx = nr.downToGrainAlways(curX + dx) - curX;
3868
5885
                                }
 
5886
                                if (explanation != null && topX != null)
 
5887
                                {
 
5888
                                        explanation.append("rect at " + TextUtils.formatDistance(topX.getMinX()) + "<=X<=" +
 
5889
                                                TextUtils.formatDistance(topX.getMaxX()) + " and " +
 
5890
                                                TextUtils.formatDistance(topX.getMinY()) + "<=Y<=" + TextUtils.formatDistance(topX.getMaxY()) +
 
5891
                                                " which is " + TextUtils.formatDistance(fromSurround[0]));
 
5892
                                        if (fromSurround[0] != fromSurround[1]) explanation.append("/" + TextUtils.formatDistance(fromSurround[1]));
 
5893
                                        explanation.append(" from rect " + TextUtils.formatDistance(lX) + "<=X<=" + TextUtils.formatDistance(hX) + " and " +
 
5894
                                                TextUtils.formatDistance(lY) + "<=Y<=" + TextUtils.formatDistance(hY));
 
5895
                                }
3869
5896
                                return dx;
3870
5897
                        }
3871
5898
                        if (dx < 0)
3872
5899
                        {
3873
 
                                dx = nr.upToGrain(lX + metalSpacingX) - curX;
 
5900
                                dx = nr.upToGrain(lX + halfWidth) - curX;
 
5901
                                if (fromTaperLen >= 0 && !sv.isOffInitialSegment() && -dx > fromTaperLen) dx = -fromTaperLen;
 
5902
                                if (curZ == toZ && curY == toY && curX > toX && curX+dx < toX) dx = toX - curX;
3874
5903
                                if (curX + dx < toX && curY >= toRect.getMinY() && curY <= toRect.getMaxY() && curZ == toZ) dx = toX - curX; else
3875
5904
                                {
3876
5905
                                        if (!inDestGrid(toRectGridded, curX+dx, curY))
3877
 
                                                dx = nr.getUpperXGrid(curZ, curX+dx) - curX;
 
5906
                                                dx = nr.getUpperXGrid(curZ, curX+dx).getCoordinate() - curX;
3878
5907
                                        if (globalRoutingDelta != 0)
3879
5908
                                        {
3880
5909
                                                Rectangle2D limit = orderedBuckets[sv.globalRoutingBucket];
3886
5915
                                                        // if moved into a new bucket, center it
3887
5916
                                                        if (curX >= originalBucket.getMinX() && curX >= originalBucket.getMaxX() && curX + dx < originalBucket.getMinX())
3888
5917
                                                                dx += originalBucket.getWidth()/2;
3889
 
                                                        dx = nr.getClosestXGrid(curZ, curX+dx) - curX;
 
5918
                                                        dx = nr.getClosestXGrid(curZ, curX+dx).getCoordinate() - curX;
3890
5919
                                                }
3891
5920
                                        }
3892
5921
                                        if (curX + dx > toRect.getMaxX() || curX + dx < toRect.getMinX()) dx = nr.upToGrainAlways(curX + dx) - curX;
3893
5922
                                }
 
5923
                                if (explanation != null && botX != null)
 
5924
                                {
 
5925
                                        explanation.append("rect at " + TextUtils.formatDistance(botX.getMinX()) + "<=X<=" +
 
5926
                                                TextUtils.formatDistance(botX.getMaxX()) + " and " +
 
5927
                                                TextUtils.formatDistance(botX.getMinY()) + "<=Y<=" + TextUtils.formatDistance(botX.getMaxY()) +
 
5928
                                                " which is " + TextUtils.formatDistance(fromSurround[0]));
 
5929
                                        if (fromSurround[0] != fromSurround[1]) explanation.append("/" + TextUtils.formatDistance(fromSurround[1]));
 
5930
                                        explanation.append(" from rect " + TextUtils.formatDistance(lX) + "<=X<=" + TextUtils.formatDistance(hX) + " and " +
 
5931
                                                TextUtils.formatDistance(lY) + "<=Y<=" + TextUtils.formatDistance(hY));
 
5932
                                }
3894
5933
                                return dx;
3895
5934
                        }
3896
5935
                        if (dy > 0)
3897
5936
                        {
3898
 
                                dy = nr.downToGrain(hY - metalSpacingY) - curY;
 
5937
                                dy = nr.downToGrain(hY - halfWidth) - curY;
 
5938
                                if (fromTaperLen >= 0 && !sv.isOffInitialSegment() && dy > fromTaperLen) dy = fromTaperLen;
 
5939
                                if (curZ == toZ && curX == toX && curY < toY && curY+dy > toY) dy = toY - curY;
3899
5940
                                if (curX >= toRect.getMinX() && curX <= toRect.getMaxX() && curY + dy > toY && curZ == toZ) dy = toY - curY; else
3900
5941
                                {
3901
5942
                                        if (!inDestGrid(toRectGridded, curX, curY+dy))
3902
 
                                                dy = nr.getLowerYGrid(curZ, curY+dy) - curY;
 
5943
                                                dy = nr.getLowerYGrid(curZ, curY+dy).getCoordinate() - curY;
3903
5944
                                        if (globalRoutingDelta != 0)
3904
5945
                                        {
3905
5946
                                                Rectangle2D limit = orderedBuckets[sv.globalRoutingBucket];
3911
5952
                                                        // if moved into a new bucket, center it
3912
5953
                                                        if (curY >= originalBucket.getMinY() && curY >= originalBucket.getMaxY() && curY + dy > originalBucket.getMaxY())
3913
5954
                                                                dy -= originalBucket.getHeight()/2;
3914
 
                                                        dy = nr.getClosestYGrid(curZ, curY+dy) - curY;
 
5955
                                                        dy = nr.getClosestYGrid(curZ, curY+dy).getCoordinate() - curY;
3915
5956
                                                }
3916
5957
                                        }
3917
5958
                                        if (curY + dy > toRect.getMaxY() || curY + dy < toRect.getMinY()) dy = nr.downToGrainAlways(curY + dy) - curY;
3918
5959
                                }
 
5960
                                if (explanation != null && topY != null)
 
5961
                                {
 
5962
                                        explanation.append("rect at " + TextUtils.formatDistance(topY.getMinX()) + "<=X<=" +
 
5963
                                                TextUtils.formatDistance(topY.getMaxX()) + " and " +
 
5964
                                                TextUtils.formatDistance(topY.getMinY()) + "<=Y<=" + TextUtils.formatDistance(topY.getMaxY()) +
 
5965
                                                " which is " + TextUtils.formatDistance(fromSurround[0]));
 
5966
                                        if (fromSurround[0] != fromSurround[1]) explanation.append("/" + TextUtils.formatDistance(fromSurround[1]));
 
5967
                                        explanation.append(" from rect " + TextUtils.formatDistance(lX) + "<=X<=" + TextUtils.formatDistance(hX) + " and " +
 
5968
                                                TextUtils.formatDistance(lY) + "<=Y<=" + TextUtils.formatDistance(hY));
 
5969
                                }
3919
5970
                                return dy;
3920
5971
                        }
3921
5972
                        if (dy < 0)
3922
5973
                        {
3923
 
                                dy = nr.upToGrain(lY + metalSpacingY) - curY;
 
5974
                                dy = nr.upToGrain(lY + halfWidth) - curY;
 
5975
                                if (fromTaperLen >= 0 && !sv.isOffInitialSegment() && -dy > fromTaperLen) dy = -fromTaperLen;
 
5976
                                if (curZ == toZ && curX == toX && curY > toY && curY+dy < toY) dy = toY - curY;
3924
5977
                                if (curX >= toRect.getMinX() && curX <= toRect.getMaxX() && curY + dy < toY && curZ == toZ) dy = toY - curY; else
3925
5978
                                {
3926
5979
                                        if (!inDestGrid(toRectGridded, curX, curY+dy))
3927
 
                                                dy = nr.getUpperYGrid(curZ, curY+dy) - curY;
 
5980
                                        {
 
5981
                                                dy = nr.getUpperYGrid(curZ, curY+dy).getCoordinate() - curY;
 
5982
                                        }
3928
5983
                                        if (globalRoutingDelta != 0)
3929
5984
                                        {
3930
5985
                                                Rectangle2D limit = orderedBuckets[sv.globalRoutingBucket];
3936
5991
                                                        // if moved into a new bucket, center it
3937
5992
                                                        if (curY >= originalBucket.getMinY() && curY >= originalBucket.getMaxY() && curY + dy < originalBucket.getMinY())
3938
5993
                                                                dy += originalBucket.getHeight()/2;
3939
 
                                                        dy = nr.getClosestYGrid(curZ, curY+dy) - curY;
 
5994
                                                        dy = nr.getClosestYGrid(curZ, curY+dy).getCoordinate() - curY;
3940
5995
                                                }
3941
5996
                                        }
3942
5997
                                        if (curY + dy > toRect.getMaxY() || curY + dy < toRect.getMinY()) dy = nr.upToGrainAlways(curY + dy) - curY;
3943
5998
                                }
 
5999
                                if (explanation != null && botY != null)
 
6000
                                {
 
6001
                                        explanation.append("rect at " + TextUtils.formatDistance(botY.getMinX()) + "<=X<=" +
 
6002
                                                TextUtils.formatDistance(botY.getMaxX()) + " and " +
 
6003
                                                TextUtils.formatDistance(botY.getMinY()) + "<=Y<=" + TextUtils.formatDistance(botY.getMaxY()) +
 
6004
                                                " which is " + TextUtils.formatDistance(fromSurround[0]));
 
6005
                                        if (fromSurround[0] != fromSurround[1]) explanation.append("/" + TextUtils.formatDistance(fromSurround[1]));
 
6006
                                        explanation.append(" from rect " + TextUtils.formatDistance(lX) + "<=X<=" + TextUtils.formatDistance(hX) + " and " +
 
6007
                                                TextUtils.formatDistance(lY) + "<=Y<=" + TextUtils.formatDistance(hY));
 
6008
                                }
3944
6009
                                return dy;
3945
6010
                        }
3946
6011
                        return 0;
3956
6021
                 * @param svCurrent the list of SearchVertex's for finding notch errors in the current path.
3957
6022
                 * @return a blocking SOGBound object that is in the area. Returns null if the area is clear.
3958
6023
                 */
3959
 
                private SOGBound getMetalBlockageAndNotch(int metNo, double halfWidth, double halfHeight,
3960
 
                        double x, double y, SearchVertex svCurrent)
 
6024
                private SOGBound getMetalBlockageAndNotch(int metNo, int maskNo, double halfWidth, double halfHeight,
 
6025
                        double x, double y, SearchVertex svCurrent, boolean minArea)
3961
6026
                {
3962
6027
                        // get the R-Tree data for the metal layer
3963
 
                        Layer layer = metalLayers[metNo];
3964
 
                        BlockageTree bTree = rTrees.getMetalTree(layer);
 
6028
                        if (maskNo > 0) maskNo--;
 
6029
                        Layer layer = metalLayers[metNo][maskNo];
 
6030
                        Layer primaryLayer = primaryMetalLayer[metNo];
 
6031
                        BlockageTree bTree = rTrees.getMetalTree(primaryLayer);
3965
6032
                        bTree.lock();
3966
6033
                        try {
3967
6034
                                if (bTree.isEmpty()) return null;
3968
6035
 
3969
6036
                                // determine the size and width/length of this piece of metal
3970
 
                                double minWidth = nr.minWidth;
3971
6037
                                double metLX = x - halfWidth, metHX = x + halfWidth;
3972
6038
                                double metLY = y - halfHeight, metHY = y + halfHeight;
3973
6039
                                Rectangle2D metBound = new Rectangle2D.Double(metLX, metLY, metHX - metLX, metHY - metLY);
3975
6041
                                double metLen = Math.max(halfWidth, halfHeight) * 2;
3976
6042
 
3977
6043
                                // determine the area to search about the metal
3978
 
                                double surround = worstMetalSurround[metNo];
3979
 
                                double lX = metLX - surround, hX = metHX + surround;
3980
 
                                double lY = metLY - surround, hY = metHY + surround;
 
6044
                                double surroundX = metalSurroundX[metNo], surroundY = metalSurroundY[metNo];
 
6045
                                double lX = metLX - surroundX, hX = metHX + surroundX;
 
6046
                                double lY = metLY - surroundY, hY = metHY + surroundY;
3981
6047
                                Rectangle2D searchArea = new Rectangle2D.Double(lX, lY, hX - lX, hY - lY);
3982
6048
 
3983
6049
                                // prepare for notch detection
 
6050
                                List<Rectangle2D> nodeRecsOnPath = new ArrayList<Rectangle2D>();
3984
6051
                                List<Rectangle2D> recsOnPath = new ArrayList<Rectangle2D>();
3985
6052
 
3986
6053
                                // make a list of rectangles on the path
3995
6062
                                                if (sv.getZ() != lastSv.getZ())
3996
6063
                                                {
3997
6064
                                                        // changed layers: compute via rectangles
3998
 
                                                        List<MetalVia> nps = metalVias[Math.min(sv.getZ(), lastSv.getZ())].getVias();
 
6065
                                                        int metNum = Math.min(sv.getZ(), lastSv.getZ());
 
6066
                                                        List<MetalVia> nps = metalVias[metNum].getVias();
 
6067
                                                        if (nr.is2X(metNum, sv.getX(), sv.getY(), sv.getX(), sv.getY()) ||
 
6068
                                                                (metNum+1 < numMetalLayers && nr.is2X(metNum+1, sv.getX(), sv.getY(), sv.getX(), sv.getY())))
 
6069
                                                        {
 
6070
                                                                List<MetalVia> nps2X = metalVias2X[metNum].getVias();
 
6071
                                                                if (nps2X.size() > 0) nps = nps2X;
 
6072
                                                        }
3999
6073
                                                        int whichContact = lastSv.getContactNo();
4000
6074
                                                        MetalVia mv = nps.get(whichContact);
4001
6075
                                                        PrimitiveNode np = mv.via;
4003
6077
                                                        SizeOffset so = np.getProtoSizeOffset();
4004
6078
                                                        double xOffset = so.getLowXOffset() + so.getHighXOffset();
4005
6079
                                                        double yOffset = so.getLowYOffset() + so.getHighYOffset();
4006
 
                                                        double wid = Math.max(np.getDefWidth(ep) - xOffset, minWidth) + xOffset;
4007
 
                                                        double hei = Math.max(np.getDefHeight(ep) - yOffset, minWidth) + yOffset;
 
6080
                                                        double wid = Math.max(np.getDefWidth(ep) - xOffset, nr.minWidth) + xOffset;
 
6081
                                                        double hei = Math.max(np.getDefHeight(ep) - yOffset, nr.minWidth) + yOffset;
4008
6082
                                                        NodeInst ni = NodeInst.makeDummyInstance(np, ep, EPoint.fromLambda(sv.getX(), sv.getY()), wid, hei, orient);
4009
6083
                                                        FixpTransform trans = null;
4010
6084
                                                        if (orient != Orientation.IDENT) trans = ni.rotateOut();
4018
6092
                                                                if (bound.getMaxX() <= lX || bound.getMinX() >= hX || bound.getMaxY() <= lY || bound.getMinY() >= hY)
4019
6093
                                                                        continue;
4020
6094
                                                                recsOnPath.add(bound);
 
6095
                                                                nodeRecsOnPath.add(bound);
4021
6096
                                                        }
4022
6097
                                                        continue;
4023
6098
                                                }
4024
6099
 
4025
6100
                                                // stayed on one layer: compute arc rectangle
4026
 
                                                double width = nr.getArcWidth(metNo);
 
6101
                                                double width = nr.getArcWidth(metNo, lastSv.getX(), lastSv.getY(), sv.getX(), sv.getY());
4027
6102
                                                Point2D head = new Point2D.Double(sv.getX(), sv.getY());
4028
6103
                                                Point2D tail = new Point2D.Double(lastSv.getX(), lastSv.getY());
4029
6104
                                                int ang = 0;
4035
6110
                                                if (bound.getMaxX() <= lX || bound.getMinX() >= hX || bound.getMaxY() <= lY || bound.getMinY() >= hY)
4036
6111
                                                        continue;
4037
6112
                                                recsOnPath.add(bound);
 
6113
                                                if (!minArea) nodeRecsOnPath.add(bound);
4038
6114
                                        }
4039
6115
                                }
4040
6116
 
4103
6179
 
4104
6180
                                // consider notch errors in the existing path
4105
6181
                                double[] spacing = nr.getSpacingRule(metNo, Math.min(metWid, metLen), Math.max(metWid, metLen));
4106
 
                                for(Rectangle2D bound : recsOnPath)
 
6182
                                for(Rectangle2D bound : nodeRecsOnPath)
4107
6183
                                {
4108
6184
                                        if (foundANotch(bTree, metBound, bound, nr.netID, recsOnPath, spacing))
4109
 
                                                return new SOGBound(ERectangle.fromLambda(bound), nr.netID);
 
6185
                                                return new SOGBound(ERectangle.fromLambda(bound), nr.netID, maskNo);
4110
6186
                                }
4111
6187
                                return null;
4112
6188
                        } finally {
4317
6393
        }
4318
6394
 
4319
6395
        /**
 
6396
         * Class to store additional geometry needed by SearchVertex contacts to ensure minimum area.
 
6397
         */
 
6398
        public static class SearchVertexAddon
 
6399
        {
 
6400
                private Rectangle2D addedGeometry;
 
6401
                private PrimitiveNode pureLayerNode;
 
6402
 
 
6403
                public SearchVertexAddon(Rectangle2D geom, PrimitiveNode pNp)
 
6404
                {
 
6405
                        addedGeometry = geom;
 
6406
                        pureLayerNode = pNp;
 
6407
                }
 
6408
 
 
6409
                public Rectangle2D getGeometry() { return addedGeometry; }
 
6410
 
 
6411
                public PrimitiveNode getPureLayerNode() { return pureLayerNode; }
 
6412
        }
 
6413
 
 
6414
        /**
4320
6415
         * Class to define a vertex in the Dijkstra search.
4321
6416
         */
4322
6417
        public static class SearchVertex implements Comparable<SearchVertex>
4323
6418
        {
 
6419
                private static final int OFFINITIALSEGMENT = 1;
 
6420
                private static final int TOOFARFROMEND = 2;
 
6421
                private static final int CLOSETOEND = 4;
 
6422
 
4324
6423
                /** the coordinate of the search vertex. */             private final double xv, yv;
4325
 
                /** the layer of the search vertex. */                  private final int zv;
 
6424
                /** the layer of the search vertex. */                  private int zv, cv;
4326
6425
                /** the cost of search to this vertex. */               private int cost;
4327
6426
                /** the layer of cuts in "cuts". */                             private int cutLayer;
4328
6427
                /** auto-generation of intermediate vertices */ private int autoGen;
 
6428
                /** the state of this vertex. */                                private int flags;
4329
6429
                /** index of global-routing bucket progress */  private int globalRoutingBucket;
4330
 
                /** the cuts in the contact. */                                 private Point2D[] cuts;
 
6430
                /** the cuts in the contact. */                                 private Rectangle2D[] cutRects;
4331
6431
                /** the size of the contact. */                                 private Point2D size;
4332
6432
                /** the previous vertex in the search. */               private SearchVertex last;
4333
 
                /** the routing state. */                                               private final Wavefront wf;
 
6433
                /** the routing state. */                                               private Wavefront wf;
 
6434
                /** added geometry for minimum area. */                 private SearchVertexAddon addOn;
4334
6435
 
4335
6436
                /**
4336
6437
                 * Method to create a new SearchVertex.
4338
6439
                 * @param y the Y coordinate of the SearchVertex.
4339
6440
                 * @param z the Z coordinate (metal layer) of the SearchVertex.
4340
6441
                 * @param whichContact the contact number to use if switching layers.
4341
 
                 * @param cuts an array of cuts in this contact (if switching layers).
 
6442
                 * @param cutRects an array of cuts in this contact (if switching layers).
4342
6443
                 * @param cl the layer of the cut (if switching layers).
4343
6444
                 * @param w the Wavefront that this SearchVertex is part of.
4344
6445
                 */
4345
 
                SearchVertex(double x, double y, int z, int whichContact, Point2D[] cuts, Point2D size, int cl, Wavefront w)
 
6446
                SearchVertex(double x, double y, int z, int c, int whichContact, Rectangle2D[] cutRects, Point2D size, int cl, Wavefront w, int flags)
4346
6447
                {
4347
6448
                        xv = x;
4348
6449
                        yv = y;
4349
6450
                        zv = (z << 8) + (whichContact & 0xFF);
4350
 
                        this.cuts = cuts;
 
6451
                        cv = c;
 
6452
                        this.cutRects = cutRects;
4351
6453
                        this.size = size;
4352
6454
                        cutLayer = cl;
4353
6455
                        autoGen = -1;
 
6456
                        this.flags = flags;
4354
6457
                        globalRoutingBucket = -1;
4355
6458
                        wf = w;
 
6459
                        addOn = null;
4356
6460
                }
4357
6461
 
4358
6462
                public double getX() { return xv; }
4361
6465
 
4362
6466
                public int getZ() { return zv >> 8; }
4363
6467
 
 
6468
                public String describeMetal()
 
6469
                {
 
6470
                        String ret = "M" + (getZ()+1);
 
6471
                        if (cv > 0) ret += (char)('a' + cv - 1);
 
6472
                        return ret;
 
6473
                }
 
6474
 
 
6475
                public int getC() { return cv; }
 
6476
 
4364
6477
                public SearchVertex getLast() { return last; }
4365
6478
 
4366
6479
                public int getCost() { return cost; }
4367
6480
 
 
6481
                public SearchVertexAddon getMoreGeometry() { return addOn; }
 
6482
 
 
6483
                public void setMoreGeometry(SearchVertexAddon sva) { addOn = sva; }
 
6484
 
4368
6485
                public int getGRBucket() { return globalRoutingBucket; }
4369
6486
 
4370
6487
                public Wavefront getWavefront() { return wf; }
4371
6488
 
4372
6489
                int getContactNo() { return zv & 0xFF; }
4373
6490
 
4374
 
                Point2D[] getCuts() { return cuts; }
 
6491
                Rectangle2D[] getCutRects() { return cutRects; }
4375
6492
 
4376
6493
                Point2D getSize() { return size; }
4377
6494
 
4378
 
                void clearCuts() { cuts = null; }
4379
 
 
4380
6495
                int getCutLayer() { return cutLayer; }
4381
6496
 
4382
6497
                int getAutoGen() { return autoGen; }
4391
6506
                void setAutoGen(int a) { autoGen = a; }
4392
6507
 
4393
6508
                /**
 
6509
                 * Method to tell whether this SearchVertex is off the initial segment.
 
6510
                 * This is determined by whether a layer change has occurred.
 
6511
                 * @return true if this SearchVertex is on the initial segment.
 
6512
                 */
 
6513
                public boolean isOffInitialSegment() { return (flags&OFFINITIALSEGMENT) != 0; }
 
6514
 
 
6515
                /**
 
6516
                 * Method to tell whether this SearchVertex cannot connect to the end of the route.
 
6517
                 * If it switched to a taper layer but did it too far from the end,
 
6518
                 * it cannot finish the route.
 
6519
                 * @return true if this SearchVertex cannot connect to the end of the route.
 
6520
                 */
 
6521
                public boolean isCantCompleteRoute() { return (flags&TOOFARFROMEND) != 0; }
 
6522
 
 
6523
                /**
 
6524
                 * Method to tell whether this SearchVertex must connect to the end of the route.
 
6525
                 * If it switched to a taper layer close to the end,
 
6526
                 * it has taper size and must finish the route.
 
6527
                 * @return true if this SearchVertex must connect to the end of the route.
 
6528
                 */
 
6529
                public boolean isMustCompleteRoute() { return (flags&CLOSETOEND) != 0; }
 
6530
 
 
6531
                /**
4394
6532
                 * Method to sort SearchVertex objects by their cost.
4395
6533
                 */
4396
6534
                public int compareTo(SearchVertex svo)
4399
6537
                        if (diff != 0) return diff;
4400
6538
                        if (wf != null)
4401
6539
                        {
4402
 
                                double thisDist = Math.abs(xv - wf.toX) + Math.abs(yv - wf.toY) + Math.abs(zv - wf.toZ);
4403
 
                                double otherDist = Math.abs(svo.xv - wf.toX) + Math.abs(svo.yv - wf.toY) + Math.abs(svo.zv - wf.toZ);
 
6540
                                double thisDist = Math.abs(xv - wf.toX) + Math.abs(yv - wf.toY) + Math.abs(getZ() - wf.toZ);
 
6541
                                double otherDist = Math.abs(svo.xv - wf.toX) + Math.abs(svo.yv - wf.toY) + Math.abs(svo.getZ() - wf.toZ);
4404
6542
                                if (thisDist < otherDist) return -1;
4405
6543
                                if (thisDist > otherDist) return 1;
4406
6544
                        }
4407
6545
                        return 0;
4408
6546
                }
4409
6547
 
4410
 
                private void generateIntermediateVertex(NeededRoute nr, int lastDirection, FixpRectangle toRectGridded)
 
6548
                private void generateIntermediateVertex(int lastDirection, FixpRectangle toRectGridded, Cell cell)
4411
6549
                {
 
6550
                        NeededRoute nr = wf.nr;
4412
6551
                        SearchVertex prevSV = last;
4413
6552
                        double dX = 0, dY = 0;
4414
6553
                        if (getX() > prevSV.getX()) dX = -1; else
4417
6556
                                                if (getY() < prevSV.getY()) dY = 1;
4418
6557
                        if (dX == 0 && dY == 0) return;
4419
6558
                        int z = getZ();
 
6559
                        int c = getC();
4420
6560
                        double newX = getX();
4421
6561
                        double newY = getY();
4422
 
                        if (dX < 0)
4423
 
                        {
4424
 
                                newX -= GRAINSIZE;
4425
 
                                if (!inDestGrid(toRectGridded, newX, newY)) newX = nr.getLowerXGrid(z, newX);
4426
 
                        }
4427
 
                        if (dX > 0)
4428
 
                        {
4429
 
                                newX += GRAINSIZE;
4430
 
                                if (!inDestGrid(toRectGridded, newX, newY)) newX = nr.getUpperXGrid(z, newX);
4431
 
                        }
4432
 
                        if (dY < 0)
4433
 
                        {
4434
 
                                newY -= GRAINSIZE;
4435
 
                                if (!inDestGrid(toRectGridded, newX, newY)) newY = nr.getLowerYGrid(z, newY);
4436
 
                        }
4437
 
                        if (dY > 0)
4438
 
                        {
4439
 
                                newY += GRAINSIZE;
4440
 
                                if (!inDestGrid(toRectGridded, newX, newY)) newY = nr.getUpperYGrid(z, newY);
4441
 
                        }
4442
6562
 
4443
6563
                        for(;;)
4444
6564
                        {
 
6565
                                if (dX < 0)
 
6566
                                {
 
6567
                                        if (nr.forceGridArcs[z])
 
6568
                                        {
 
6569
                                                newX = nr.getLowerXGrid(z, newX-GRAINSIZE).getCoordinate();
 
6570
                                        } else
 
6571
                                        {
 
6572
                                                newX -= GRAINSIZE;
 
6573
                                                if (!inDestGrid(toRectGridded, newX, newY)) newX = nr.getLowerXGrid(z, newX).getCoordinate();
 
6574
                                        }
 
6575
                                }
 
6576
                                if (dX > 0)
 
6577
                                {
 
6578
                                        if (nr.forceGridArcs[z])
 
6579
                                        {
 
6580
                                                newX = nr.getUpperXGrid(z, newX+GRAINSIZE).getCoordinate();
 
6581
                                        } else
 
6582
                                        {
 
6583
                                                newX += GRAINSIZE;
 
6584
                                                if (!inDestGrid(toRectGridded, newX, newY)) newX = nr.getUpperXGrid(z, newX).getCoordinate();
 
6585
                                        }
 
6586
                                }
 
6587
                                if (dY < 0)
 
6588
                                {
 
6589
                                        if (nr.forceGridArcs[z])
 
6590
                                        {
 
6591
                                                newY = nr.getLowerYGrid(z, newY-GRAINSIZE).getCoordinate();
 
6592
                                        } else
 
6593
                                        {
 
6594
                                                newY -= GRAINSIZE;
 
6595
                                                if (!inDestGrid(toRectGridded, newX, newY)) newY = nr.getLowerYGrid(z, newY).getCoordinate();
 
6596
                                        }
 
6597
                                }
 
6598
                                if (dY > 0)
 
6599
                                {
 
6600
                                        if (nr.forceGridArcs[z])
 
6601
                                        {
 
6602
                                                newY = nr.getUpperYGrid(z, newY+GRAINSIZE).getCoordinate();
 
6603
                                        } else
 
6604
                                        {
 
6605
                                                newY += GRAINSIZE;
 
6606
                                                if (!inDestGrid(toRectGridded, newX, newY)) newY = nr.getUpperYGrid(z, newY).getCoordinate();
 
6607
                                        }
 
6608
                                }
4445
6609
                                if (dX < 0 && newX <= prevSV.getX()) break;
4446
6610
                                if (dX > 0 && newX >= prevSV.getX()) break;
4447
6611
                                if (dY < 0 && newY <= prevSV.getY()) break;
4448
6612
                                if (dY > 0 && newY >= prevSV.getY()) break;
4449
6613
                                if (wf.getVertex(newX, newY, z) == null)
4450
6614
                                {
4451
 
                                        SearchVertex svIntermediate = new SearchVertex(newX, newY, z, getContactNo(), getCuts(), getSize(), z, wf);
 
6615
                                        SearchVertex svIntermediate = new SearchVertex(newX, newY, z, c, getContactNo(), getCutRects(), getSize(), z, wf, last.flags);
 
6616
                                        if (wf.debuggingWavefront) RoutingDebug.ensureDebuggingShadow(svIntermediate, false);
4452
6617
                                        if (wf.globalRoutingDelta != 0)
4453
6618
                                                svIntermediate.globalRoutingBucket = wf.getNextBucket(this, newX, newY);
4454
6619
                                        svIntermediate.setAutoGen(lastDirection);
4458
6623
                                        wf.active.add(svIntermediate);
4459
6624
                                        break;
4460
6625
                                }
4461
 
                                if (dX < 0)
4462
 
                                {
4463
 
                                        newX -= GRAINSIZE;
4464
 
                                        if (!inDestGrid(toRectGridded, newX, newY)) newX = nr.getLowerXGrid(z, newX);
4465
 
                                }
4466
 
                                if (dX > 0)
4467
 
                                {
4468
 
                                        newX += GRAINSIZE;
4469
 
                                        if (!inDestGrid(toRectGridded, newX, newY)) newX = nr.getUpperXGrid(z, newX);
4470
 
                                }
4471
 
                                if (dY < 0)
4472
 
                                {
4473
 
                                        newY -= GRAINSIZE;
4474
 
                                        if (!inDestGrid(toRectGridded, newX, newY)) newY = nr.getLowerYGrid(z, newY);
4475
 
                                }
4476
 
                                if (dY > 0)
4477
 
                                {
4478
 
                                        newY += GRAINSIZE;
4479
 
                                        if (!inDestGrid(toRectGridded, newX, newY)) newY = nr.getUpperYGrid(z, newY);
4480
 
                                }
4481
6626
                        }
4482
6627
                }
4483
6628
        }
4490
6635
         */
4491
6636
        private boolean initializeDesignRules()
4492
6637
        {
4493
 
                // find the metal layers, arcs, and contacts
4494
 
                numMetalLayers = tech.getNumMetals();
4495
 
                metalLayers = new Layer[numMetalLayers];
4496
 
                metalArcs = new ArcProto[numMetalLayers];
 
6638
                // find the number of metal layers
 
6639
                numMetalLayers = 0;
 
6640
                for(Iterator<Layer> it = tech.getLayers(); it.hasNext(); )
 
6641
                {
 
6642
                        Layer lay = it.next();
 
6643
                        if (!lay.getFunction().isMetal()) continue;
 
6644
                        int metNum = lay.getFunction().getLevel();
 
6645
                        numMetalLayers = Math.max(metNum, numMetalLayers);
 
6646
                }
 
6647
                for(Iterator<ArcProto> it = tech.getArcs(); it.hasNext(); )
 
6648
                {
 
6649
                        ArcProto ap = it.next();
 
6650
                        if (!ap.getFunction().isMetal()) continue;
 
6651
                        int metNum = ap.getFunction().getLevel();
 
6652
                        numMetalLayers = Math.max(metNum, numMetalLayers);
 
6653
                }
 
6654
 
 
6655
                // load up the metal layers
 
6656
                metalLayers = new Layer[numMetalLayers][];
 
6657
                primaryMetalLayer = new Layer[numMetalLayers];
 
6658
                List<Layer>[] tempLayerList = new List[numMetalLayers];
 
6659
                for(int i=0; i<numMetalLayers; i++) tempLayerList[i] = new ArrayList<Layer>();
 
6660
                for(Iterator<Layer> it = tech.getLayers(); it.hasNext(); )
 
6661
                {
 
6662
                        Layer lay = it.next();
 
6663
                        if (!lay.getFunction().isMetal()) continue;
 
6664
                        int metNum = lay.getFunction().getLevel() - 1;
 
6665
                        tempLayerList[metNum].add(lay);
 
6666
                }
 
6667
                for(int i=0; i<numMetalLayers; i++)
 
6668
                {
 
6669
                        primaryMetalLayer[i] = null;
 
6670
                        Collections.sort(tempLayerList[i], new SortLayersByMaskNumber());
 
6671
                        if (tempLayerList[i].size() > 1)
 
6672
                        {
 
6673
                                // multiple layers for this metal: see if an uncolored layer is mixed with colored ones
 
6674
                                Layer first = tempLayerList[i].get(0);
 
6675
                        int colorNum = first.getFunction().getMaskColor();
 
6676
                        if (colorNum == 0) { primaryMetalLayer[i] = tempLayerList[i].get(0);  tempLayerList[i].remove(0); }
 
6677
                        }
 
6678
                        metalLayers[i] = new Layer[tempLayerList[i].size()];
 
6679
                        for(int c=0; c<tempLayerList[i].size(); c++) metalLayers[i][c] = tempLayerList[i].get(c);
 
6680
                        if (primaryMetalLayer[i] == null) primaryMetalLayer[i] = metalLayers[i][0];
 
6681
                }
 
6682
 
 
6683
                // load up the metal arcs
 
6684
                metalArcs = new ArcProto[numMetalLayers][];
 
6685
                metalPureLayerNodes = new PrimitiveNode[numMetalLayers][];
 
6686
                primaryMetalArc = new ArcProto[numMetalLayers];
 
6687
                size2X = new double[numMetalLayers];
 
6688
                taperLength = new double[numMetalLayers];
 
6689
                boolean hasFavorites = false;
4497
6690
                favorArcs = new boolean[numMetalLayers];
4498
6691
                preventArcs = new boolean[numMetalLayers];
 
6692
                taperOnlyArcs = new boolean[numMetalLayers];
 
6693
                for(int i=0; i<numMetalLayers; i++)
 
6694
                        favorArcs[i] = preventArcs[i] = taperOnlyArcs[i] = false;
 
6695
                List<ArcProto>[] tempArcList = new List[numMetalLayers];
 
6696
                for(int i=0; i<numMetalLayers; i++) tempArcList[i] = new ArrayList<ArcProto>();
 
6697
                for(Iterator<ArcProto> it = tech.getArcs(); it.hasNext(); )
 
6698
                {
 
6699
                        ArcProto ap = it.next();
 
6700
                        if (!ap.getFunction().isMetal()) continue;
 
6701
                        int metNum = ap.getFunction().getLevel() - 1;
 
6702
                        tempArcList[metNum].add(ap);
 
6703
                }
 
6704
                for(int i=0; i<numMetalLayers; i++)
 
6705
                {
 
6706
                        primaryMetalArc[i] = null;
 
6707
                        Collections.sort(tempArcList[i], new SortArcsByMaskNumber());
 
6708
                        if (tempArcList[i].size() > 1)
 
6709
                        {
 
6710
                                // multiple layers for this metal: see if an uncolored layer is mixed with colored ones
 
6711
                                ArcProto first = tempArcList[i].get(0);
 
6712
                        int colorNum = first.getMaskLayer();
 
6713
                        if (colorNum == 0) { primaryMetalArc[i] = tempArcList[i].get(0);  tempArcList[i].remove(0); }
 
6714
                        }
 
6715
                        metalArcs[i] = new ArcProto[tempArcList[i].size()];
 
6716
                        metalPureLayerNodes[i] = new PrimitiveNode[tempArcList[i].size()];
 
6717
                        for(int c=0; c<tempArcList[i].size(); c++)
 
6718
                        {
 
6719
                                ArcProto ap = tempArcList[i].get(c);
 
6720
                                int metNum = ap.getFunction().getLevel() - 1;
 
6721
                                metalArcs[i][c] = ap;
 
6722
                                for(Iterator<PrimitiveNode> it = tech.getNodes(); it.hasNext(); )
 
6723
                                {
 
6724
                                        PrimitiveNode pNp = it.next();
 
6725
                                        if (pNp.getFunction() != PrimitiveNode.Function.NODE) continue;
 
6726
                                        for(Iterator<Layer> lIt = pNp.getLayerIterator(); lIt.hasNext(); )
 
6727
                                        {
 
6728
                                                Layer lay = lIt.next();
 
6729
                                                if (!lay.getFunction().isMetal()) continue;
 
6730
                                                if (lay.getFunction().getLevel()-1 != metNum) continue;
 
6731
                                                if (lay.getFunction().getMaskColor() != ap.getMaskLayer()) continue;
 
6732
                                                metalPureLayerNodes[i][c] = pNp;
 
6733
                                                break;
 
6734
                                        }
 
6735
                                        if (metalPureLayerNodes[i][c] != null) break;
 
6736
                                }
 
6737
                                if (sogp.isFavored(ap))
 
6738
                                {
 
6739
                                        favorArcs[metNum] = true;
 
6740
                                        hasFavorites = true;
 
6741
                                }
 
6742
                                if (sogp.isPrevented(ap)) preventArcs[metNum] = true;
 
6743
                                if (sogp.isTaperOnly(ap)) taperOnlyArcs[metNum] = true;
 
6744
                        }
 
6745
                        if (primaryMetalArc[i] == null) primaryMetalArc[i] = metalArcs[i][0];
 
6746
 
 
6747
                        Double d = sogp.get2XWidth(primaryMetalArc[i]);
 
6748
                        if (d == null) size2X[i] = 0; else size2X[i] = d.doubleValue();
 
6749
                        d = sogp.getTaperLength(primaryMetalArc[i]);
 
6750
                        if (d == null) taperLength[i] = -1; else taperLength[i] = d.doubleValue();
 
6751
                }
 
6752
                if (!hasFavorites)
 
6753
                        for (int i = 0; i < numMetalLayers; i++) favorArcs[i] = true;
 
6754
 
 
6755
                // do error checking
 
6756
                boolean failure = false;
 
6757
                for(int i=0; i<numMetalLayers; i++)
 
6758
                {
 
6759
                        if (metalLayers[i].length == 0)
 
6760
                        {
 
6761
                                error("Cannot find layer for Metal " + (i+1) + " in technology " + tech.getTechName());
 
6762
                                failure = true;
 
6763
                        }
 
6764
                        if (metalArcs[i].length == 0)
 
6765
                        {
 
6766
                                error("Cannot find arc for Metal " + (i+1) + " in technology " + tech.getTechName());
 
6767
                                failure = true;
 
6768
                        }
 
6769
                        for(int c=0; c<metalPureLayerNodes[i].length; c++)
 
6770
                        {
 
6771
                                if (metalPureLayerNodes[i][c] == null)
 
6772
                                {
 
6773
                                        error("Cannot find pure-layer node for Metal " + (i+1) + " color " + (c+1) + " in technology " + tech.getTechName());
 
6774
                                        failure = true;
 
6775
                                }
 
6776
                        }
 
6777
                        if (metalLayers[i].length != metalArcs[i].length)
 
6778
                        {
 
6779
                                String layMsg = "";
 
6780
                                for(int c=0; c<metalLayers[i].length; c++)
 
6781
                                {
 
6782
                                        if (layMsg.length() > 0) layMsg += ", ";
 
6783
                                        layMsg += metalLayers[i][c].getName();
 
6784
                                }
 
6785
                                String arcMsg = "";
 
6786
                                for(int c=0; c<metalArcs[i].length; c++)
 
6787
                                {
 
6788
                                        if (arcMsg.length() > 0) arcMsg += ", ";
 
6789
                                        arcMsg += metalArcs[i][c].getName();
 
6790
                                }
 
6791
                                warn("Metal " + (i+1) + " in technology " + tech.getTechName() + " has " + metalLayers[i].length +
 
6792
                                        " mask layers (" + layMsg + ") but " + metalArcs[i].length + " mask arcs (" + arcMsg + "). Making them equal length.");
 
6793
                                if (metalLayers[i].length > metalArcs[i].length)
 
6794
                                {
 
6795
                                        Layer[] newMetalLayers = new Layer[metalArcs[i].length];
 
6796
                                        for(int c=0; c<newMetalLayers.length; c++) newMetalLayers[c] = metalLayers[i][c];
 
6797
                                        metalLayers[i] = newMetalLayers;
 
6798
                                } else
 
6799
                                {
 
6800
                                        ArcProto[] newMetalArcs = new ArcProto[metalLayers[i].length];
 
6801
                                        for(int c=0; c<newMetalArcs.length; c++) newMetalArcs[c] = metalArcs[i][c];
 
6802
                                        metalArcs[i] = newMetalArcs;
 
6803
                                }
 
6804
                        }
 
6805
                        if (metalLayers[i].length == metalArcs[i].length)
 
6806
                        {
 
6807
                                boolean badOrder = false;
 
6808
                                String layMsg = "", arcMsg = "";
 
6809
                                for(int c=0; c<metalLayers[i].length; c++)
 
6810
                                {
 
6811
                                        int layMask = metalLayers[i][c].getFunction().getMaskColor();
 
6812
                                        int arcMask = metalArcs[i][c].getMaskLayer();
 
6813
                                        if (layMsg.length() > 0) layMsg += ", ";
 
6814
                                        layMsg += layMask;
 
6815
                                        if (arcMsg.length() > 0) arcMsg += ", ";
 
6816
                                        arcMsg += arcMask;
 
6817
                                        if (layMask != arcMask) badOrder = true;
 
6818
                                }
 
6819
                                if (badOrder)
 
6820
                                {
 
6821
                                        error("Metal " + (i+1) + " in technology " + tech.getTechName() + " has layer masks " + layMsg + " but arc masks " + arcMsg);
 
6822
                                        failure = true;
 
6823
                                }
 
6824
                        }
 
6825
                }
 
6826
                if (failure) return true;
 
6827
 
 
6828
                // find the layers that remove metal
 
6829
                removeLayers = new HashMap<Layer,Layer>();
 
6830
                for(int i=0; i<numMetalLayers; i++)
 
6831
                {
 
6832
                        for(int j=0; j<metalLayers[i].length; j++)
 
6833
                        {
 
6834
                                Layer metLay = metalLayers[i][j];
 
6835
                                ArcProto metAp = metalArcs[i][j];
 
6836
                                String removeLayerName = sogp.getRemoveLayer(metAp);
 
6837
                                if (removeLayerName == null) continue;
 
6838
                                Layer removeLay = tech.findLayer(removeLayerName);
 
6839
                                if (removeLay == null) System.out.println("WARNING: Unknown removal layer: " + removeLayerName); else
 
6840
                                        removeLayers.put(removeLay, metLay);
 
6841
                        }
 
6842
                }
 
6843
 
 
6844
                // now gather the via information
4499
6845
                viaLayers = new Layer[numMetalLayers - 1];
4500
6846
                metalVias = new MetalVias[numMetalLayers - 1];
4501
6847
                for (int i = 0; i < numMetalLayers - 1; i++)
4502
6848
                        metalVias[i] = new MetalVias();
4503
 
                for (Iterator<Layer> it = tech.getLayers(); it.hasNext();)
4504
 
                {
4505
 
                        Layer lay = it.next();
4506
 
                        if (!lay.getFunction().isMetal()) continue;
4507
 
                        int layerIndex = lay.getFunction().getLevel() - 1;
4508
 
                        if (layerIndex < numMetalLayers)  metalLayers[layerIndex] = lay;
4509
 
                }
4510
 
                boolean hasFavorites = false;
4511
 
                for (Iterator<ArcProto> it = tech.getArcs(); it.hasNext(); )
4512
 
                {
4513
 
                        ArcProto ap = it.next();
4514
 
                        for (int i = 0; i < numMetalLayers; i++)
4515
 
                        {
4516
 
                                if (ap.getLayer(0) == metalLayers[i])
4517
 
                                {
4518
 
                                        metalArcs[i] = ap;
4519
 
                                        favorArcs[i] = sogp.isFavored(ap);
4520
 
                                        if (favorArcs[i]) hasFavorites = true;
4521
 
                                        preventArcs[i] = sogp.isPrevented(ap);
4522
 
                                        break;
4523
 
                                }
4524
 
                        }
4525
 
                }
4526
 
                if (!hasFavorites)
4527
 
                        for (int i = 0; i < numMetalLayers; i++) favorArcs[i] = true;
 
6849
                metalVias2X = new MetalVias[numMetalLayers - 1];
 
6850
                for (int i = 0; i < numMetalLayers - 1; i++)
 
6851
                        metalVias2X[i] = new MetalVias();
4528
6852
 
4529
6853
                // regular expression to discard some primitives
4530
6854
                String ignorePattern = sogp.getIgnorePrimitives();              // "Z-(\\w+)"
4531
 
                String acceptPattern = sogp.getAcceptOnlyPrimitives();  // "X-(\\w+)"
 
6855
                String accept1XPattern = sogp.getAcceptOnly1XPrimitives();      // "X-(\\w+)"
 
6856
                String accept2XPattern = sogp.getAcceptOnly2XPrimitives();  // "R-(\\w+)"
4532
6857
                boolean contactsCanRotate = sogp.isContactsRotate();
4533
6858
                Pattern ignorePat = (ignorePattern != null) ? Pattern.compile(ignorePattern) : null;
4534
 
                Pattern acceptPat = (acceptPattern != null) ? Pattern.compile(acceptPattern) : null;
 
6859
                Pattern acceptPat1X = (accept1XPattern != null) ? Pattern.compile(accept1XPattern) : null;
 
6860
                Pattern acceptPat2X = (accept2XPattern != null) ? Pattern.compile(accept2XPattern) : null;
4535
6861
                for (Iterator<PrimitiveNode> it = tech.getNodes(); it.hasNext();)
4536
6862
                {
4537
6863
                        PrimitiveNode np = it.next();
4545
6871
                                if (matcher.find()) continue;
4546
6872
                        }
4547
6873
 
4548
 
                        if (acceptPat != null)
4549
 
                        {
4550
 
                                // Match not found and therefore not using this primitive
4551
 
                                Matcher matcher = acceptPat.matcher(np.getName());
4552
 
                                if (!matcher.find()) continue;
4553
 
                        }
4554
 
 
4555
 
                        ArcProto[] conns = np.getPort(0).getConnections();
4556
 
                        for (int i = 0; i < numMetalLayers - 1; i++)
4557
 
                        {
4558
 
                                if ((conns[0] == metalArcs[i] && conns[1] == metalArcs[i + 1]) ||
4559
 
                                        (conns[1] == metalArcs[i] && conns[0] == metalArcs[i + 1]))
 
6874
                        // see if this is a 1X or 2X contact
 
6875
                        boolean is1XContact = false, is2XContact = false;
 
6876
                        if (acceptPat1X == null) is1XContact = true; else
 
6877
                        {
 
6878
                                Matcher matcher = acceptPat1X.matcher(np.getName());
 
6879
                                is1XContact = matcher.find();
 
6880
                        }
 
6881
                        if (acceptPat2X == null) is2XContact = true; else
 
6882
                        {
 
6883
                                Matcher matcher = acceptPat2X.matcher(np.getName());
 
6884
                                is2XContact = matcher.find();
 
6885
                        }
 
6886
                        if (is1XContact || is2XContact)
 
6887
                        {
 
6888
                                MetalVias[] whichOnes = is1XContact ? metalVias : metalVias2X;
 
6889
                                ArcProto[] conns = np.getPort(0).getConnections();
 
6890
                                for (int i = 0; i < numMetalLayers - 1; i++)
4560
6891
                                {
4561
 
                                        // see if the node is asymmetric and should exist in rotated states
4562
 
                                        boolean square = true, offCenter = false;
4563
 
                                        NodeInst dummyNi = NodeInst.makeDummyInstance(np, ep);
4564
 
                                        Poly[] conPolys = tech.getShapeOfNode(dummyNi);
4565
 
                                        int horMet = -1, verMet = -1;
4566
 
                                        double horMetInset = 0, verMetInset = 0;
4567
 
                                        for (int p = 0; p < conPolys.length; p++)
 
6892
                                        if ((isOnMetalArc(i, conns[0]) && isOnMetalArc(i+1, conns[1])) ||
 
6893
                                                (isOnMetalArc(i, conns[1]) && isOnMetalArc(i+1, conns[0])))
4568
6894
                                        {
4569
 
                                                Poly conPoly = conPolys[p];
4570
 
                                                Layer conLayer = conPoly.getLayer();
4571
 
                                                Layer.Function lFun = conLayer.getFunction();
4572
 
                                                if (lFun.isMetal())
 
6895
                                                // see if the node is asymmetric and should exist in rotated states
 
6896
                                                boolean square = true, offCenter = false;
 
6897
                                                NodeInst dummyNi = NodeInst.makeDummyInstance(np, ep);
 
6898
                                                Poly[] conPolys = tech.getShapeOfNode(dummyNi);
 
6899
                                                int horMet = -1, verMet = -1;
 
6900
                                                double horMetInset = 0, verMetInset = 0;
 
6901
                                                int horMetColor = 0, verMetColor = 0;
 
6902
                                                for (int p = 0; p < conPolys.length; p++)
4573
6903
                                                {
4574
 
                                                        Rectangle2D conRect = conPoly.getBounds2D();
4575
 
                                                        if (conRect.getWidth() != conRect.getHeight())
 
6904
                                                        Poly conPoly = conPolys[p];
 
6905
                                                        Layer conLayer = conPoly.getLayer();
 
6906
                                                        Layer.Function lFun = conLayer.getFunction();
 
6907
                                                        if (lFun.isMetal())
4576
6908
                                                        {
4577
 
                                                                square = false;
4578
 
                                                                if (conRect.getWidth() > conRect.getHeight())
4579
 
                                                                {
4580
 
                                                                        // horizontal piece
4581
 
                                                                        horMet = lFun.getLevel() - 1;
4582
 
                                                                        horMetInset = dummyNi.getYSize() - conRect.getHeight();
4583
 
                                                                } else
4584
 
                                                                {
4585
 
                                                                        // vertical piece
4586
 
                                                                        verMet = lFun.getLevel() - 1;
4587
 
                                                                        verMetInset = dummyNi.getXSize() - conRect.getWidth();
 
6909
                                                                Rectangle2D conRect = conPoly.getBounds2D();
 
6910
                                                                if (conRect.getWidth() != conRect.getHeight())
 
6911
                                                                {
 
6912
                                                                        square = false;
 
6913
                                                                        if (conRect.getWidth() > conRect.getHeight())
 
6914
                                                                        {
 
6915
                                                                                // horizontal piece
 
6916
                                                                                horMet = lFun.getLevel() - 1;
 
6917
                                                                                horMetColor = lFun.getMaskColor();
 
6918
                                                                                horMetInset = dummyNi.getYSize() - conRect.getHeight();
 
6919
                                                                        } else
 
6920
                                                                        {
 
6921
                                                                                // vertical piece
 
6922
                                                                                verMet = lFun.getLevel() - 1;
 
6923
                                                                                verMetColor = lFun.getMaskColor();
 
6924
                                                                                verMetInset = dummyNi.getXSize() - conRect.getWidth();
 
6925
                                                                        }
4588
6926
                                                                }
 
6927
                                                                if (conRect.getCenterX() != 0 || conRect.getCenterY() != 0) offCenter = true;
 
6928
                                                        } else if (lFun.isContact())
 
6929
                                                        {
 
6930
                                                                viaLayers[i] = conLayer;
4589
6931
                                                        }
4590
 
                                                        if (conRect.getCenterX() != 0 || conRect.getCenterY() != 0) offCenter = true;
4591
 
                                                } else if (lFun.isContact())
4592
 
                                                {
4593
 
                                                        viaLayers[i] = conLayer;
4594
6932
                                                }
4595
 
                                        }
4596
6933
 
4597
 
                                        if (square || offCenter) horMet = verMet = -1; else
4598
 
                                                if (horMet < 0 || verMet < 0) horMet = verMet = -1;
4599
 
                                        metalVias[i].addVia(np, 0, horMet, horMetInset, verMet, verMetInset);
4600
 
                                        if (contactsCanRotate)
4601
 
                                        {
4602
 
                                                if (offCenter)
4603
 
                                                {
4604
 
                                                        // off center: test in all 4 rotations
4605
 
                                                        metalVias[i].addVia(np, 90, horMet, horMetInset, verMet, verMetInset);
4606
 
                                                        metalVias[i].addVia(np, 180, horMet, horMetInset, verMet, verMetInset);
4607
 
                                                        metalVias[i].addVia(np, 270, horMet, horMetInset, verMet, verMetInset);
4608
 
                                                } else if (!square)
4609
 
                                                {
4610
 
                                                        // centered but not square: test in 90-degree rotation
4611
 
                                                        metalVias[i].addVia(np, 90, verMet, verMetInset, horMet, horMetInset);
 
6934
                                                if (square || offCenter) horMet = verMet = -1; else
 
6935
                                                        if (horMet < 0 || verMet < 0) horMet = verMet = -1;
 
6936
                                                whichOnes[i].addVia(np, 0, horMet, horMetColor, horMetInset, verMet, verMetColor, verMetInset);
 
6937
                                                if (contactsCanRotate)
 
6938
                                                {
 
6939
                                                        if (offCenter)
 
6940
                                                        {
 
6941
                                                                // off center: test in all 4 rotations
 
6942
                                                                whichOnes[i].addVia(np, 90, horMet, horMetColor, horMetInset, verMet, verMetColor, verMetInset);
 
6943
                                                                whichOnes[i].addVia(np, 180, horMet, horMetColor, horMetInset, verMet, verMetColor, verMetInset);
 
6944
                                                                whichOnes[i].addVia(np, 270, horMet, horMetColor, horMetInset, verMet, verMetColor, verMetInset);
 
6945
                                                        } else if (!square)
 
6946
                                                        {
 
6947
                                                                // centered but not square: test in 90-degree rotation
 
6948
                                                                whichOnes[i].addVia(np, 90, verMet, verMetColor, verMetInset, horMet, horMetColor, horMetInset);
 
6949
                                                        }
4612
6950
                                                }
 
6951
                                                break;
4613
6952
                                        }
4614
 
                                        break;
4615
6953
                                }
4616
6954
                        }
4617
6955
                }
4618
 
                for (int i = 0; i < numMetalLayers; i++)
 
6956
                for (int i = 0; i < numMetalLayers-1; i++)
4619
6957
                {
4620
 
                        if (metalLayers[i] == null)
4621
 
                        {
4622
 
                                error("Cannot find layer for Metal " + (i + 1));
4623
 
                                return true;
4624
 
                        }
4625
 
                        if (metalArcs[i] == null)
4626
 
                        {
4627
 
                                error("Cannot find arc for Metal " + (i + 1));
4628
 
                                return true;
4629
 
                        }
4630
 
                        if (i < numMetalLayers - 1)
4631
 
                        {
4632
 
                                boolean noContact = false;
4633
 
                                if (metalVias[i].getVias().size() == 0)
4634
 
                                {
4635
 
                                        warn("Cannot find contact node between Metal " + (i+1) + " and Metal " + (i+2) + " in technology " + tech.getTechName() +
4636
 
                                                ". Ignoring Metal layers " + (i+2) + " and higher.");
4637
 
                                        noContact = true;
4638
 
                                } else if (viaLayers[i] == null)
4639
 
                                {
4640
 
                                        warn("Cannot find contact layer between Metal " + (i+1) + " and Metal " + (i+2) + " in technology " + tech.getTechName() +
4641
 
                                                ". Ignoring Metal layers " + (i+2) + " and higher.");
4642
 
                                        noContact = true;
4643
 
                                }
4644
 
                                if (noContact)
4645
 
                                {
4646
 
                                        for(int j=i+1; j<numMetalLayers; j++)
4647
 
                                                preventArcs[j] = true;
4648
 
                                        break;
4649
 
                                }
 
6958
                        // check that the vias span all of the masks
 
6959
                        if (metalArcs[i].length > 1 || metalArcs[i+1].length > 1)
 
6960
                        {
 
6961
                                boolean[][] masks = new boolean[metalArcs[i].length][metalArcs[i+1].length];
 
6962
                                for(int c1=0; c1<metalArcs[i].length; c1++)
 
6963
                                        for(int c2=0; c2<metalArcs[i+1].length; c2++) masks[c1][c2] = false;
 
6964
                                List<MetalVia> allContacts = new ArrayList<MetalVia>();
 
6965
                                for(MetalVia mv : metalVias[i].getVias())
 
6966
                                        allContacts.add(mv);
 
6967
                                for(MetalVia mv : metalVias2X[i].getVias())
 
6968
                                        allContacts.add(mv);
 
6969
                                for(MetalVia mv : allContacts)
 
6970
                                {
 
6971
                                        int met1 = -1, met1c = -1, met2 = -1, met2c = -1;
 
6972
                                        for(NodeLayer nl : mv.via.getNodeLayers())
 
6973
                                        {
 
6974
                                                Layer layer = nl.getLayer();
 
6975
                                                if (layer.getFunction().isMetal())
 
6976
                                                {
 
6977
                                                        if (met1 < 0)
 
6978
                                                        {
 
6979
                                                                met1 = layer.getFunction().getLevel();
 
6980
                                                                met1c = layer.getFunction().getMaskColor();
 
6981
                                                        } else
 
6982
                                                        {
 
6983
                                                                met2 = layer.getFunction().getLevel();
 
6984
                                                                met2c = layer.getFunction().getMaskColor();
 
6985
                                                        }
 
6986
                                                }
 
6987
                                        }
 
6988
                                        if (met1 < 0 || met2 < 0) continue;
 
6989
                                        if (met1 != i+1 || met2 != i+2)
 
6990
                                        {
 
6991
                                                warn("Contact " + mv.via.getName() + " in technology " + tech.getTechName() +
 
6992
                                                        " bridges metals " + (i+1) + " and " + (i+2) + " but mentions different metals in its name");
 
6993
                                                continue;
 
6994
                                        }
 
6995
                                        if (met1c == 0)
 
6996
                                        {
 
6997
                                                if (metalArcs[i].length > 1)
 
6998
                                                        warn("Contact " + mv.via.getName() + " in technology " + tech.getTechName() +
 
6999
                                                                " does not specify mask for metal " + (i+1));
 
7000
                                                met1c = 1;
 
7001
                                        }
 
7002
                                        if (met2c == 0)
 
7003
                                        {
 
7004
                                                if (metalArcs[i+1].length > 1)
 
7005
                                                        warn("Contact " + mv.via.getName() + " in technology " + tech.getTechName() +
 
7006
                                                                " does not specify mask for metal " + (i+2));
 
7007
                                                met2c = 1;
 
7008
                                        }
 
7009
                                        masks[met1c-1][met2c-1] = true;
 
7010
                                }
 
7011
                                for(int c1=0; c1<metalArcs[i].length; c1++)
 
7012
                                {
 
7013
                                        for(int c2=0; c2<metalArcs[i+1].length; c2++)
 
7014
                                        {
 
7015
                                                if (masks[c1][c2]) continue;
 
7016
                                                warn("No metal-" + (i+1) + " to metal-" + (i+2) + " contact in technology " + tech.getTechName() +
 
7017
                                                        " that bridges metal-" + (i+1) + "/mask-" + (c1+1) + " and metal-" + (i+2) + "/mask-" + (c2+1));
 
7018
                                        }
 
7019
                                }
 
7020
                        }
 
7021
 
 
7022
                        boolean noContact = false;
 
7023
                        if (metalVias[i].getVias().size() == 0)
 
7024
                        {
 
7025
                                warn("Cannot find contact node between Metal " + (i+1) + " and Metal " + (i+2) + " in technology " + tech.getTechName() +
 
7026
                                        ". Ignoring Metal layers " + (i+2) + " and higher.");
 
7027
                                noContact = true;
 
7028
                        } else if (viaLayers[i] == null)
 
7029
                        {
 
7030
                                warn("Cannot find contact layer between Metal " + (i+1) + " and Metal " + (i+2) + " in technology " + tech.getTechName() +
 
7031
                                        ". Ignoring Metal layers " + (i+2) + " and higher.");
 
7032
                                noContact = true;
 
7033
                        }
 
7034
                        if (noContact)
 
7035
                        {
 
7036
                                for(int j=i+1; j<numMetalLayers; j++)
 
7037
                                        preventArcs[j] = true;
 
7038
                                break;
4650
7039
                        }
4651
7040
                }
4652
7041
 
 
7042
 
4653
7043
                // compute design rule spacings
 
7044
        DRC.DRCPreferences dp = new DRC.DRCPreferences(false);
 
7045
                minResolution = dp.getResolution(tech).getLambda();
4654
7046
                layerSurround = new Map[numMetalLayers];
4655
7047
                for (int i = 0; i < numMetalLayers; i++)
4656
7048
                        layerSurround[i] = new HashMap<Double, Map<Double, double[]>>();
4657
 
                metalSurround = new double[numMetalLayers];
4658
 
                worstMetalSurround = new double[numMetalLayers];
 
7049
                metalSurroundX = new double[numMetalLayers];
 
7050
                metalSurroundY = new double[numMetalLayers];
 
7051
                maxDefArcWidth = new double[numMetalLayers];
 
7052
                minimumArea = new double[numMetalLayers];
4659
7053
                MutableDouble mutableDist = new MutableDouble(0);
4660
7054
                for (int i = 0; i < numMetalLayers; i++)
4661
7055
                {
4662
 
                        DRCTemplate rule = DRC.getSpacingRule(metalLayers[i], null, metalLayers[i], null, false, -1, metalArcs[i].getDefaultLambdaBaseWidth(ep), 50);
4663
 
                        metalSurround[i] = 0;
4664
 
                        if (rule != null) metalSurround[i] = rule.getValue(0);
4665
 
                        if (DRC.getMaxSurround(metalLayers[i], Double.MAX_VALUE, mutableDist)) // only when found
4666
 
                                worstMetalSurround[i] = mutableDist.doubleValue();
 
7056
                        if (metalLayers[i] == null) continue;
 
7057
                        
 
7058
                        // get minimum area rule
 
7059
                        minimumArea[i] = 0;
 
7060
                DRCTemplate minAreaRule = DRC.getMinValue(primaryMetalLayer[i], DRCTemplate.DRCRuleType.MINAREA);
 
7061
                if (minAreaRule != null)
 
7062
                        minimumArea[i] = minAreaRule.getValue(0);
 
7063
 
 
7064
                // get surrounds
 
7065
                metalSurroundX[i] = metalSurroundY[i] = maxDefArcWidth[i] = 0;
 
7066
                        for(int c=0; c<metalArcs[i].length; c++)
 
7067
                        {
 
7068
                                maxDefArcWidth[i] = Math.max(maxDefArcWidth[i], metalArcs[i][c].getDefaultLambdaBaseWidth(ep));
 
7069
                                DRCTemplate rule = DRC.getSpacingRule(metalLayers[i][c], null, metalLayers[i][c], null, false, -1,
 
7070
                                        metalArcs[i][c].getDefaultLambdaBaseWidth(ep), 50);
 
7071
                                if (rule != null)
 
7072
                                {
 
7073
                                        metalSurroundX[i] = Math.max(metalSurroundX[i], rule.getValue(0));
 
7074
                                        if (rule.getNumValues() > 1)
 
7075
                                        {
 
7076
                                                metalSurroundY[i] = Math.max(metalSurroundY[i], rule.getValue(1));
 
7077
                                        } else
 
7078
                                        {
 
7079
                                                metalSurroundY[i] = metalSurroundX[i];
 
7080
                                        }
 
7081
                                }
 
7082
                                if (DRC.getMaxSurround(metalLayers[i][c], Double.MAX_VALUE, mutableDist)) // only when found
 
7083
                                {
 
7084
                                        metalSurroundX[i] = Math.max(metalSurroundX[i], mutableDist.doubleValue());
 
7085
                                        if (metalSurroundY[i] != mutableDist.doubleValue())
 
7086
                                                metalSurroundY[i] = Math.max(metalSurroundY[i], mutableDist.doubleValue());
 
7087
                                }
 
7088
                        }
4667
7089
                }
4668
7090
                viaSurround = new double[numMetalLayers - 1];
 
7091
                viaSize = new double[numMetalLayers - 1];
4669
7092
                for (int i = 0; i < numMetalLayers - 1; i++)
4670
7093
                {
4671
7094
                        Layer lay = viaLayers[i];
4672
7095
                        if (lay == null) continue;
4673
7096
 
4674
7097
                        double spacing = 2;
4675
 
                        double arcWidth = metalArcs[i].getDefaultLambdaBaseWidth(ep);
4676
 
                        DRCTemplate ruleSpacing = DRC.getSpacingRule(lay, null, lay, null, false, -1, arcWidth, 50);
 
7098
                        DRCTemplate ruleSpacing = DRC.getSpacingRule(lay, null, lay, null, false, -1, maxDefArcWidth[i], 50);
4677
7099
                        if (ruleSpacing != null) spacing = ruleSpacing.getValue(0);
4678
7100
 
4679
7101
                        // determine cut size
4682
7104
                        if (ruleWidth != null) width = ruleWidth.getValue(0);
4683
7105
 
4684
7106
                        // extend to the size of the largest cut
4685
 
                        List<MetalVia> nps = metalVias[i].getVias();
 
7107
                        List<MetalVia> nps = new ArrayList<MetalVia>();
 
7108
                        for(MetalVia mv : metalVias[i].getVias()) nps.add(mv);
 
7109
                        for(MetalVia mv : metalVias2X[i].getVias()) nps.add(mv);
4686
7110
                        for (MetalVia mv : nps)
4687
7111
                        {
4688
7112
                                NodeInst dummyNi = NodeInst.makeDummyInstance(mv.via, ep);
4699
7123
                                }
4700
7124
                        }
4701
7125
 
4702
 
                        viaSurround[i] = spacing + width;
 
7126
                        viaSurround[i] = spacing;
 
7127
                        viaSize[i] = width;
4703
7128
                }
4704
7129
                return false;
4705
7130
        }
4706
7131
 
4707
 
// debugging code
 
7132
    /**
 
7133
     * Comparator class for sorting Layers by their mask number.
 
7134
     */
 
7135
    private static class SortLayersByMaskNumber implements Comparator<Layer>
 
7136
    {
 
7137
        public int compare(Layer l1, Layer l2)
 
7138
        {
 
7139
                int m1 = l1.getFunction().getMaskColor();
 
7140
                int m2 = l2.getFunction().getMaskColor();
 
7141
            return m1 - m2;
 
7142
        }
 
7143
    }
 
7144
 
 
7145
 
 
7146
    /**
 
7147
     * Comparator class for sorting ArcProtos by their mask number.
 
7148
     */
 
7149
    private static class SortArcsByMaskNumber implements Comparator<ArcProto>
 
7150
    {
 
7151
        public int compare(ArcProto a1, ArcProto a2)
 
7152
        {
 
7153
                int m1 = a1.getMaskLayer();
 
7154
                int m2 = a2.getMaskLayer();
 
7155
            return m1 - m2;
 
7156
        }
 
7157
    }
 
7158
 
 
7159
    // debugging code
4708
7160
//      private void dumpSpacing()
4709
7161
//      {
4710
7162
//              System.out.println("CACHED METAL SPACINGS");
4747
7199
 
4748
7200
        private void initializeGrids()
4749
7201
        {
4750
 
                metalGrid = new double[numMetalLayers][];
 
7202
                metalGrid = new SeaOfGatesTrack[numMetalLayers][];
4751
7203
                metalGridRange = new double[numMetalLayers];
4752
7204
                for(int i=0; i<numMetalLayers; i++)
4753
7205
                {
4754
 
                        ArcProto ap = metalArcs[i];
 
7206
                        ArcProto ap = primaryMetalArc[i];
4755
7207
                        String arcGrid = sogp.getGrid(ap);
4756
7208
                        if (arcGrid == null)
4757
7209
                        {
4759
7211
                                metalGridRange[i] = 0;
4760
7212
                        } else
4761
7213
                        {
4762
 
                                List<Double> found = new ArrayList<Double>();
 
7214
                                List<SeaOfGates.SeaOfGatesTrack> found = new ArrayList<SeaOfGates.SeaOfGatesTrack>();
4763
7215
                                String[] parts = arcGrid.split(",");
4764
7216
                                for(int j=0; j<parts.length; j++)
4765
7217
                                {
4766
7218
                                        String part = parts[j].trim();
4767
7219
                                        if (part.length() == 0) continue;
 
7220
                                        int trackColor = SeaOfGatesTrack.getSpecificMaskNumber(part);
 
7221
                                        if (!Character.isDigit(part.charAt(part.length()-1))) part = part.substring(0, part.length()-1);
4768
7222
                                        double val = TextUtils.atof(part);
4769
 
                                        found.add(new Double(val));
 
7223
                                        found.add(new SeaOfGates.SeaOfGatesTrack(val, trackColor));
4770
7224
                                }
4771
 
                                metalGrid[i] = new double[found.size()];
4772
 
                                for(int j=0; j<found.size(); j++) metalGrid[i][j] = found.get(j).doubleValue();
4773
 
                                metalGridRange[i] = metalGrid[i][found.size()-1] - metalGrid[i][0];
 
7225
                                Collections.sort(found);
 
7226
                                metalGrid[i] = new SeaOfGatesTrack[found.size()];
 
7227
                                for(int j=0; j<found.size(); j++) metalGrid[i][j] = found.get(j);
 
7228
                                metalGridRange[i] = metalGrid[i][found.size()-1].getCoordinate() - metalGrid[i][0].getCoordinate();
4774
7229
                        }
4775
7230
                }
4776
7231
        }
4794
7249
                        neededRoutes = new ArrayList<NeededRoute>();
4795
7250
                }
4796
7251
 
4797
 
                public void addUnorderedPort(PortInst pi)
 
7252
                public boolean addUnorderedPort(PortInst pi)
4798
7253
                {
4799
7254
                        if (pi.getNodeInst().isCellInstance() ||
4800
7255
                                ((PrimitiveNode)pi.getNodeInst().getProto()).getTechnology() != Generic.tech())
4801
7256
                        {
4802
7257
                                if (!unorderedPorts.contains(pi)) unorderedPorts.add(pi);
 
7258
                                return false;
4803
7259
                        }
 
7260
                        return true;
4804
7261
                }
4805
7262
 
4806
7263
                /**
4900
7357
 
4901
7358
        private RouteBatch[] makeListOfRoutes(Netlist netList, List<ArcInst> arcsToRoute, List<EPoint> linesInNonMahnattan)
4902
7359
        {
 
7360
                // normal condition: organize arcs by network
 
7361
                Map<Network,List<ArcInst>> seen = new HashMap<Network,List<ArcInst>>();
 
7362
                for (int b = 0; b < arcsToRoute.size(); b++)
 
7363
                {
 
7364
                        // get list of PortInsts that comprise this net
 
7365
                        ArcInst ai = arcsToRoute.get(b);
 
7366
                        Network net = netList.getNetwork(ai, 0);
 
7367
                        if (net == null)
 
7368
                        {
 
7369
                                warn("Arc " + describe(ai) + " has no network!");
 
7370
                                continue;
 
7371
                        }
 
7372
                        List<ArcInst> arcsOnNet = seen.get(net);
 
7373
                        if (arcsOnNet == null) seen.put(net, arcsOnNet = new ArrayList<ArcInst>());
 
7374
 
 
7375
                        // remove duplicates
 
7376
                        boolean exists = false;
 
7377
                        for(ArcInst oldAI : arcsOnNet)
 
7378
                        {
 
7379
                                if (oldAI.getHeadPortInst().getPortProto() == ai.getHeadPortInst().getPortProto() &&
 
7380
                                        oldAI.getHeadPortInst().getNodeInst() == ai.getHeadPortInst().getNodeInst() &&
 
7381
                                        oldAI.getTailPortInst().getPortProto() == ai.getTailPortInst().getPortProto() &&
 
7382
                                        oldAI.getTailPortInst().getNodeInst() == ai.getTailPortInst().getNodeInst()) { exists = true;  break; }
 
7383
                                if (oldAI.getHeadPortInst().getPortProto() == ai.getTailPortInst().getPortProto() &&
 
7384
                                        oldAI.getHeadPortInst().getNodeInst() == ai.getTailPortInst().getNodeInst() &&
 
7385
                                        oldAI.getTailPortInst().getPortProto() == ai.getHeadPortInst().getPortProto() &&
 
7386
                                        oldAI.getTailPortInst().getNodeInst() == ai.getHeadPortInst().getNodeInst()) { exists = true;  break; }
 
7387
                        }
 
7388
                        if (exists)
 
7389
                        {
 
7390
                                String warnMsg = "Arc from (" + TextUtils.formatDistance(ai.getHeadLocation().getX()) + "," +
 
7391
                                        TextUtils.formatDistance(ai.getHeadLocation().getY()) + ") to (" + TextUtils.formatDistance(ai.getTailLocation().getX()) + "," +
 
7392
                                        TextUtils.formatDistance(ai.getTailLocation().getY()) + ") is redundant";
 
7393
                                List<EPoint> linesToShow = new ArrayList<EPoint>();
 
7394
                                linesToShow.add(EPoint.fromLambda(ai.getHeadLocation().getX(), ai.getHeadLocation().getY()));
 
7395
                                linesToShow.add(EPoint.fromLambda(ai.getTailLocation().getX(), ai.getTailLocation().getY()));
 
7396
                                warn(warnMsg, netList.getCell(), linesToShow, null);
 
7397
                        } else
 
7398
                        {
 
7399
                                arcsOnNet.add(ai);
 
7400
                        }
 
7401
                }
 
7402
 
 
7403
                // build a RoutesOnNetwork for every network
4903
7404
                List<RoutesOnNetwork> allRoutes = new ArrayList<RoutesOnNetwork>();
4904
 
                if (!DEBUGGRIDDING && RoutingDebug.isActive() && !RoutingDebug.isRewireNetworks())
 
7405
                List<Network> allNets = new ArrayList<Network>();
 
7406
                for(Network net : seen.keySet()) allNets.add(net);
 
7407
                Collections.sort(allNets);
 
7408
                for(Network net : allNets)
4905
7409
                {
4906
 
                        // make a batch with just the first arc
4907
 
                        ArcInst ai = arcsToRoute.get(0);
4908
 
                        Network net = netList.getNetwork(ai, 0);
4909
7410
                        RoutesOnNetwork ron = new RoutesOnNetwork(net.getName());
4910
7411
                        allRoutes.add(ron);
4911
 
                        ron.unroutedArcs.add(ai);
4912
 
                        ron.addUnorderedPort(ai.getHeadPortInst());
4913
 
                        ron.addUnorderedPort(ai.getTailPortInst());
4914
 
                        ron.pairs.add(new SteinerTreePortPair(ai.getHeadPortInst(), ai.getTailPortInst()));
4915
 
                } else
4916
 
                {
4917
 
                        // organize arcs by network
4918
 
                        Map<Network,List<ArcInst>> seen = new HashMap<Network,List<ArcInst>>();
4919
 
                        for (int b = 0; b < arcsToRoute.size(); b++)
 
7412
 
 
7413
                        // make list of all ends in the batch
 
7414
                        List<ArcInst> arcsOnNet = seen.get(net);
 
7415
                        for (ArcInst ai : arcsOnNet)
4920
7416
                        {
4921
 
                                // get list of PortInsts that comprise this net
4922
 
                                ArcInst ai = arcsToRoute.get(b);
4923
 
                                Network net = netList.getNetwork(ai, 0);
4924
 
                                if (net == null)
4925
 
                                {
4926
 
                                        warn("Arc " + describe(ai) + " has no network!");
4927
 
                                        continue;
4928
 
                                }
4929
 
                                List<ArcInst> arcsOnNet = seen.get(net);
4930
 
                                if (arcsOnNet == null) seen.put(net, arcsOnNet = new ArrayList<ArcInst>());
4931
 
                                arcsOnNet.add(ai);
 
7417
                                ron.unroutedArcs.add(ai);
 
7418
                                if (ron.addUnorderedPort(ai.getHeadPortInst()))
 
7419
                                        warn("Arc " + describe(ai) + " has an unconnectable end (on " + ai.getHeadPortInst().getNodeInst().describe(false) + ")");
 
7420
                                if (ron.addUnorderedPort(ai.getTailPortInst()))
 
7421
                                        warn("Arc " + describe(ai) + " has an unconnectable end (on " + ai.getTailPortInst().getNodeInst().describe(false) + ")");
4932
7422
                        }
4933
7423
 
4934
 
                        // build a RoutesOnNetwork for every network
4935
 
                        List<Network> allNets = new ArrayList<Network>();
4936
 
                        for(Network net : seen.keySet()) allNets.add(net);
4937
 
                        Collections.sort(allNets);
4938
 
                        for(Network net : allNets)
 
7424
                        if (sogp.isSteinerDone())
4939
7425
                        {
4940
 
                                RoutesOnNetwork ron = new RoutesOnNetwork(net.getName());
4941
 
                                allRoutes.add(ron);
4942
 
 
4943
 
                                // make list of all ends in the batch
4944
 
                                List<ArcInst> arcsOnNet = seen.get(net);
4945
7426
                                for (ArcInst ai : arcsOnNet)
4946
 
                                {
4947
 
                                        ron.unroutedArcs.add(ai);
4948
 
                                        ron.addUnorderedPort(ai.getHeadPortInst());
4949
 
                                        ron.addUnorderedPort(ai.getTailPortInst());
4950
 
                                }
4951
 
 
4952
 
                                if (sogp.isSteinerDone())
4953
 
                                {
4954
 
                                        for (ArcInst ai : arcsOnNet)
4955
 
                                                ron.pairs.add(new SteinerTreePortPair(ai.getHeadPortInst(), ai.getTailPortInst()));
 
7427
                                        ron.pairs.add(new SteinerTreePortPair(ai.getHeadPortInst(), ai.getTailPortInst()));
 
7428
                        } else
 
7429
                        {
 
7430
                                // see if this is a spine route
 
7431
                                if (prefs.enableSpineRouting && ron.setupSpineInfo())
 
7432
                                {
 
7433
                                        // a spine route
4956
7434
                                } else
4957
7435
                                {
4958
 
                                        // see if this is a spine route
4959
 
                                        if (prefs.enableSpineRouting && ron.setupSpineInfo())
4960
 
                                        {
4961
 
                                                // a spine route
4962
 
                                        } else
4963
 
                                        {
4964
 
                                                // a non-spine route
4965
 
                                                List<SteinerTreePort> portList = new ArrayList<SteinerTreePort>();
4966
 
                                                for(PortInst pi : ron.unorderedPorts) portList.add(new PortInstShadow(pi));
4967
 
                                                SteinerTree st = new SteinerTree(portList);
4968
 
                                                ron.pairs = st.getTreeBranches();
4969
 
                                                if (ron.pairs == null)
 
7436
                                        // a non-spine route
 
7437
                                        List<SteinerTreePort> portList = new ArrayList<SteinerTreePort>();
 
7438
                                        for(PortInst pi : ron.unorderedPorts) portList.add(new PortInstShadow(pi));
 
7439
                                        SteinerTree st = new SteinerTree(portList);
 
7440
                                        ron.pairs = st.getTreeBranches();
 
7441
                                        if (ron.pairs == null)
 
7442
                                        {
 
7443
                                                String errMsg = "Arcs in " + net.getName() + " do not make valid connection: deleted";
 
7444
                                                error(errMsg);
 
7445
                                                List<EPoint> lineList = new ArrayList<EPoint>();
 
7446
                                                for(ArcInst delAi : ron.unroutedArcs)
4970
7447
                                                {
4971
 
                                                        String errMsg = "Arcs in " + net.getName() + " do not make valid connection: deleted";
4972
 
                                                        error(errMsg);
4973
 
                                                        List<EPoint> lineList = new ArrayList<EPoint>();
4974
 
                                                        for(ArcInst delAi : ron.unroutedArcs)
4975
 
                                                        {
4976
 
                                                                lineList.add(delAi.getHeadLocation());
4977
 
                                                                lineList.add(delAi.getTailLocation());
4978
 
                                                        }
4979
 
                                                        errorLogger.logMessageWithLines(errMsg, null, lineList, cell, 0, true);
 
7448
                                                        lineList.add(delAi.getHeadLocation());
 
7449
                                                        lineList.add(delAi.getTailLocation());
4980
7450
                                                }
 
7451
                                                errorLogger.logMessageWithLines(errMsg, null, lineList, cell, 0, true);
4981
7452
                                        }
4982
7453
                                }
4983
7454
                        }
4987
7458
                if (buildRTrees(netList, arcsToRoute, linesInNonMahnattan))
4988
7459
                {
4989
7460
                        info("Non-Manhattan geometry found");
4990
 
//                      hadNonmanhattan.setValue(true);
4991
7461
                }
4992
7462
 
4993
7463
                // make NeededRoute objects and fill-in network information in the R-Tree
5000
7470
                {
5001
7471
                        // determine the minimum width of arcs on this net
5002
7472
                        double minWidth = getMinWidth(ron.unorderedPorts);
5003
 
 
5004
7473
                        for(int i=0; i<ron.pairs.size(); i++)
5005
7474
                        {
5006
7475
                                Object obj1 = ron.pairs.get(i).getPort1();
5016
7485
                                ArcProto bArc = getMetalArcOnPort(bPi);
5017
7486
                                if (bArc == null) continue;
5018
7487
 
5019
 
                                // create the NeededRoute and the blockages around it
 
7488
                                // create the NeededRoute
5020
7489
                                NeededRoute nr = new NeededRoute(ron.netName, aPi, bPi, aArc, bArc, ron.spineTapPorts, minWidth);
5021
 
                                if (inValidPort(aPi, nr) || inValidPort(bPi, nr)) continue;
5022
 
                                ron.neededRoutes.add(nr);
5023
7490
 
 
7491
                                // set the network number on this net
5024
7492
                                Iterator<ArcInst> it = ron.unroutedArcs.iterator();
5025
7493
                                ArcInst sampleArc = it.next();
5026
7494
                                Network net = netList.getNetwork(sampleArc, 0);
5027
7495
                                nr.setNetID(net);
5028
7496
                                nr.growNetwork();
 
7497
 
 
7498
                                // check endpoints and place contacts there if needed
 
7499
                                if (nr.invalidPort(true, aPi) || nr.invalidPort(false, bPi)) continue;
 
7500
 
 
7501
                                ron.neededRoutes.add(nr);
5029
7502
                        }
5030
7503
                }
5031
7504
 
5059
7532
                        {
5060
7533
                                if (rb == null)
5061
7534
                                {
5062
 
                                        rb = new RouteBatch();
 
7535
                                        rb = new RouteBatch(ron.netName);
5063
7536
                                        allBatches.add(rb);
5064
7537
                                }
5065
7538
                                for(ArcInst ai : ron.unroutedArcs)
5114
7587
                RouteBatch[] routeBatches = new RouteBatch[allBatches.size()];
5115
7588
                for(int i=0; i<allBatches.size(); i++)
5116
7589
                        routeBatches[i] = allBatches.get(i);
 
7590
 
 
7591
                for(RouteBatch rb : allBatches)
 
7592
                {
 
7593
                        for(NeededRoute nr : rb.routesInBatch)
 
7594
                        {
 
7595
                                if (nr.spineTaps != null) nr.routeName += " (spine)"; else
 
7596
                                {
 
7597
                                        if (nr.batch.routesInBatch.size() > 1)
 
7598
                                                nr.routeName += " (" + (nr.routeInBatch+1) + " of " + nr.batch.routesInBatch.size() + ")";
 
7599
                                }
 
7600
                        }
 
7601
                }
5117
7602
                return routeBatches;
5118
7603
        }
5119
7604
 
5142
7627
        Runnable[] findPath(NeededRoute nr)
5143
7628
        {
5144
7629
                // prepare the routing path
5145
 
                Wavefront[] wavefronts = nr.makeWavefronts();
 
7630
                nr.makeWavefronts();
5146
7631
 
5147
7632
                if (nr.checkEndSurround()) return null;
5148
7633
 
5149
7634
                // special case when route is null length
5150
 
                Wavefront d1 = wavefronts[0];
5151
 
                Wavefront d2 = wavefronts[1];
 
7635
                Wavefront d1 = nr.dirAtoB;
 
7636
                Wavefront d2 = nr.dirBtoA;
5152
7637
                if (DBMath.rectsIntersect(d1.fromRect, d1.toRect) && d1.toZ == d1.fromZ)
5153
7638
                {
5154
7639
                        double xVal = (Math.max(d1.fromRect.getMinX(), d1.toRect.getMinX()) + Math.min(d1.fromRect.getMaxX(), d1.toRect.getMaxX())) / 2;
5155
7640
                        double yVal = (Math.max(d1.fromRect.getMinY(), d1.toRect.getMinY()) + Math.min(d1.fromRect.getMaxY(), d1.toRect.getMaxY())) / 2;
5156
 
                        SearchVertex sv = new SearchVertex(xVal, yVal, d1.toZ, 0, null, null, 0, d1);
 
7641
                        SearchVertex sv = new SearchVertex(xVal, yVal, d1.toZ, d1.toC, 0, null, null, 0, d1, 0);
 
7642
                        if (nr.debuggingRouteFromA != null) RoutingDebug.ensureDebuggingShadow(sv, false);
5157
7643
                        nr.completeRoute(sv);
5158
7644
                        return null;
5159
7645
                }
5236
7722
 
5237
7723
                        // run both wavefronts in parallel (interleaving steps)
5238
7724
                        SearchVertex result = null;
5239
 
                        while (result == null)
 
7725
                        SearchVertex resultA = null, resultB = null;
 
7726
                        boolean forceBothDirectionsToFinish = CHECKBOTHDIRECTIONS;
 
7727
                        if (nr.debuggingRouteFromA != null) forceBothDirectionsToFinish = true;
 
7728
                        if (forceBothDirectionsToFinish)
5240
7729
                        {
5241
 
                                SearchVertex resultA = dirAtoB.advanceWavefront();
5242
 
                                SearchVertex resultB = dirBtoA.advanceWavefront();
5243
 
                                if (resultA != null || resultB != null)
 
7730
                                while (result == null)
5244
7731
                                {
 
7732
                                        if (resultA == null) resultA = dirAtoB.advanceWavefront();
 
7733
                                        if (resultB == null) resultB = dirBtoA.advanceWavefront();
 
7734
 
 
7735
                                        // stop now if either direction aborted
5245
7736
                                        if (resultA == svAborted || resultB == svAborted)
5246
7737
                                        {
5247
7738
                                                nr.completeRoute(svAborted);
5248
7739
                                                return;
5249
7740
                                        }
5250
 
                                        if (resultA == svLimited || resultB == svLimited)
5251
 
                                        {
5252
 
                                                nr.completeRoute(svLimited);
5253
 
                                                return;
5254
 
                                        }
5255
 
                                        if (resultA == svExhausted || resultB == svExhausted)
5256
 
                                        {
5257
 
                                                nr.completeRoute(svExhausted);
5258
 
                                                return;
5259
 
                                        }
 
7741
 
 
7742
                                        // both directions must complete
 
7743
                                        if (resultA == null || resultB == null) continue;
 
7744
 
 
7745
                                        // search is done, see if they failed
 
7746
                                        if ((resultA == svLimited || resultA == svExhausted) &&
 
7747
                                                (resultB == svLimited || resultB == svExhausted))
 
7748
                                        {
 
7749
                                                // both directions failed: see if there is anything common in the two wavefronts
 
7750
                                                result = tryToFindPath(dirAtoB, dirBtoA);
 
7751
                                                if (result == null)
 
7752
                                                {
 
7753
                                                        nr.completeRoute(resultA);
 
7754
                                                        return;
 
7755
                                                }
 
7756
                                                resultA = result;
 
7757
                                        }
 
7758
 
 
7759
                                        // routing completed
 
7760
                                        boolean aGood = resultA != null && resultA != svAbandoned && resultA != svLimited && resultA != svExhausted;
 
7761
                                        boolean bGood = resultB != null && resultB != svAbandoned && resultB != svLimited && resultB != svExhausted;
 
7762
//String aNature = "succeeded";
 
7763
//if (resultA == null) aNature = "null"; else
 
7764
//      if (resultA == svAbandoned) aNature = "abandoned"; else
 
7765
//              if (resultA == svLimited) aNature = "limited"; else
 
7766
//                      if (resultA == svExhausted) aNature = "exhausted";
 
7767
//String bNature = "succeeded";
 
7768
//if (resultB == null) bNature = "null"; else
 
7769
//      if (resultB == svAbandoned) bNature = "abandoned"; else
 
7770
//              if (resultB == svLimited) bNature = "limited"; else
 
7771
//                      if (resultB == svExhausted) bNature = "exhausted";
 
7772
//System.out.println("ROUTE "+nr.routeName+" HAS A="+aNature+" AND B="+bNature);
 
7773
                                        if (aGood && bGood)
 
7774
                                        {
 
7775
                                                // both directions completed: choose the best
 
7776
                                                List<SearchVertex> aList = new ArrayList<SearchVertex>();
 
7777
                                                getOptimizedList(resultA, aList);
 
7778
                                                int aVias = 0;
 
7779
                                                double aLength = 0;
 
7780
                                                for (int i=1; i<aList.size(); i++)
 
7781
                                                {
 
7782
                                                        SearchVertex svLast = aList.get(i-1);
 
7783
                                                        SearchVertex sv = aList.get(i);
 
7784
                                                        if (svLast.getZ() != sv.getZ())
 
7785
                                                        {
 
7786
                                                                aVias++;
 
7787
                                                        } else
 
7788
                                                        {
 
7789
                                                                double dX = Math.abs(svLast.getX() - sv.getX());
 
7790
                                                                double dY = Math.abs(svLast.getY() - sv.getY());
 
7791
                                                                aLength += Math.sqrt(dY*dY + dX*dX);
 
7792
                                                        }
 
7793
                                                }
 
7794
 
 
7795
                                                List<SearchVertex> bList = new ArrayList<SearchVertex>();
 
7796
                                                getOptimizedList(resultB, bList);
 
7797
                                                int bVias = 0;
 
7798
                                                double bLength = 0;
 
7799
                                                for (int i=1; i<aList.size(); i++)
 
7800
                                                {
 
7801
                                                        SearchVertex svLast = aList.get(i-1);
 
7802
                                                        SearchVertex sv = aList.get(i);
 
7803
                                                        if (svLast.getZ() != sv.getZ())
 
7804
                                                        {
 
7805
                                                                aVias++;
 
7806
                                                        } else
 
7807
                                                        {
 
7808
                                                                double dX = Math.abs(svLast.getX() - sv.getX());
 
7809
                                                                double dY = Math.abs(svLast.getY() - sv.getY());
 
7810
                                                                bLength += Math.sqrt(dY*dY + dX*dX);
 
7811
                                                        }
 
7812
                                                }
 
7813
 
 
7814
//System.out.println("ROUTE "+nr.routeName+" HAS A-LENGTH="+TextUtils.formatDistance(aLength)+" AND B-LENGTH="+TextUtils.formatDistance(bLength));
 
7815
                                                if (aLength < bLength || (aLength == bLength && aVias < bVias))
 
7816
                                                {
 
7817
                                                        // A is better
 
7818
                                                        resultB = null;
 
7819
                                                } else
 
7820
                                                {
 
7821
                                                        // B is better
 
7822
                                                        resultA = null;
 
7823
                                                }
 
7824
                                        }
 
7825
 
5260
7826
                                        result = resultA;
5261
 
                                        if (result == null || result == svAbandoned)
5262
 
                                        {
5263
 
                                                result = resultB;
 
7827
                                        if (result == null || result == svAbandoned || result == svLimited || result == svExhausted)
 
7828
                                        {
 
7829
                                                if (resultB != svAbandoned && resultB != svLimited && resultB != svExhausted)
 
7830
                                                        result = resultB;
 
7831
                                        }
 
7832
                                }
 
7833
                        } else
 
7834
                        {
 
7835
                                // just wait until one of them terminates
 
7836
                                while (result == null)
 
7837
                                {
 
7838
                                        if (resultA == null) resultA = dirAtoB.advanceWavefront();
 
7839
                                        if (resultB == null) resultB = dirBtoA.advanceWavefront();
 
7840
                                        if (resultA != null || resultB != null)
 
7841
                                        {
 
7842
                                                if (resultA == svAborted || resultB == svAborted)
 
7843
                                                {
 
7844
                                                        nr.completeRoute(svAborted);
 
7845
                                                        return;
 
7846
                                                }
 
7847
                                                if ((resultA == svLimited || resultA == svExhausted) &&
 
7848
                                                        (resultB == svLimited || resultB == svExhausted))
 
7849
                                                {
 
7850
                                                        // see if there is anything common in the two wavefronts
 
7851
                                                        result = tryToFindPath(dirAtoB, dirBtoA);
 
7852
                                                        if (result == null)
 
7853
                                                        {
 
7854
                                                                nr.completeRoute(resultA);
 
7855
                                                                return;
 
7856
                                                        }
 
7857
                                                        resultA = result;
 
7858
                                                }
 
7859
                                                result = resultA;
 
7860
                                                if (result == null || result == svAbandoned || result == svLimited || result == svExhausted)
 
7861
                                                {
 
7862
                                                        if (resultB != svAbandoned && resultB != svLimited && resultB != svExhausted)
 
7863
                                                                result = resultB;
 
7864
                                                }
5264
7865
                                        }
5265
7866
                                }
5266
7867
                        }
5269
7870
                }
5270
7871
        }
5271
7872
 
 
7873
        /**
 
7874
         * Method to examine two failed wavefronts (from A to B and from B to A) and look for
 
7875
         * a point of intersection that would establish a successful route.
 
7876
         * @param a one Wavefront
 
7877
         * @param b the other Wavefront
 
7878
         * @return null if no path can be found. Otherwise it returns the point to unwind to do the route.
 
7879
         */
 
7880
        private SearchVertex tryToFindPath(Wavefront a, Wavefront b)
 
7881
        {
 
7882
                SearchVertex bestSVA = null, bestSVB = null;
 
7883
                double bestDistance = Double.MAX_VALUE;
 
7884
                for(int z=0; z<a.searchVertexPlanes.length; z++)
 
7885
                {
 
7886
                        Map<Integer, Map<Integer,SearchVertex>> plane = a.searchVertexPlanes[z];
 
7887
                        if (plane == null) continue;
 
7888
                        for(Integer y : plane.keySet())
 
7889
                        {
 
7890
                                Map<Integer,SearchVertex> row = plane.get(y);
 
7891
                                if (row == null) continue;
 
7892
                                double yCoord = y.intValue() / DBMath.GRID;
 
7893
                                for(Integer x : row.keySet())
 
7894
                                {
 
7895
                                        SearchVertex foundInA = row.get(x);
 
7896
                                        double xCoord = x.intValue() / DBMath.GRID;
 
7897
                                        SearchVertex foundInB = b.getVertex(xCoord, yCoord, z);
 
7898
                                        if (foundInB != null)
 
7899
                                        {
 
7900
                                                // found a common point in the two wavefronts
 
7901
                                                double total = 0;
 
7902
                                                for(SearchVertex sv = foundInA; sv != null; sv = sv.last)
 
7903
                                                {
 
7904
                                                        SearchVertex prev = sv.last;
 
7905
                                                        if (prev == null) break;
 
7906
                                                        double dX = sv.getX() - prev.getX();
 
7907
                                                        double dY = sv.getY() - prev.getY();
 
7908
                                                        total += Math.sqrt(dX*dX + dY*dY);
 
7909
                                                        if (sv.getZ() != prev.getZ()) total++;
 
7910
                                                }
 
7911
                                                for(SearchVertex sv = foundInB; sv != null; sv = sv.last)
 
7912
                                                {
 
7913
                                                        SearchVertex prev = sv.last;
 
7914
                                                        if (prev == null) break;
 
7915
                                                        double dX = sv.getX() - prev.getX();
 
7916
                                                        double dY = sv.getY() - prev.getY();
 
7917
                                                        total += Math.sqrt(dX*dX + dY*dY);
 
7918
                                                        if (sv.getZ() != prev.getZ()) total++;
 
7919
                                                }
 
7920
 
 
7921
                                                // see if this is the best so far
 
7922
                                                boolean better = DBMath.isLessThan(total, bestDistance);
 
7923
                                                if (better)
 
7924
                                                {
 
7925
                                                        bestDistance = total;
 
7926
                                                        bestSVA = foundInA;
 
7927
                                                        bestSVB = foundInB;
 
7928
                                                }
 
7929
                                        }
 
7930
                                }
 
7931
                        }
 
7932
                }
 
7933
                if (bestSVA != null)
 
7934
                {
 
7935
                        System.out.println("Network " + a.nr.routeName + " failed in both directions, but found a common point at (" +
 
7936
                                TextUtils.formatDistance(bestSVA.xv) + "," + TextUtils.formatDistance(bestSVA.yv) + ")");
 
7937
                        List<SearchVertex> halfPath = new ArrayList<SearchVertex>();
 
7938
                        while (bestSVB != null)
 
7939
                        {
 
7940
                                halfPath.add(bestSVB);
 
7941
                                bestSVB = bestSVB.last;
 
7942
                        }
 
7943
                        List<SearchVertex> path = new ArrayList<SearchVertex>();
 
7944
                        Point2D lastSize = null;
 
7945
                        Rectangle2D[] lastCuts = null;
 
7946
                        int lastCutNumber = 0;
 
7947
                        for(int i=0; i<halfPath.size(); i++)
 
7948
                        {
 
7949
                                SearchVertex thisOne = halfPath.get(i);
 
7950
                                Point2D thisSize = thisOne.size;
 
7951
                                Rectangle2D[] thisCuts = thisOne.getCutRects();
 
7952
                                int thisCutNumber = thisOne.zv & 0xFF;
 
7953
 
 
7954
                                thisOne.size = lastSize;
 
7955
                                thisOne.cutRects = lastCuts;
 
7956
                                thisOne.zv = (thisOne.zv & 0xFFFFFF00) | (lastCutNumber & 0xFF);
 
7957
 
 
7958
                                lastSize = thisSize;
 
7959
                                lastCuts = thisCuts;
 
7960
                                lastCutNumber = thisCutNumber;
 
7961
                        }
 
7962
                        for(int i=halfPath.size()-1; i>=0; i--)
 
7963
                                path.add(halfPath.get(i));
 
7964
                        while (bestSVA != null)
 
7965
                        {
 
7966
                                path.add(bestSVA);
 
7967
                                bestSVA = bestSVA.last;
 
7968
                        }
 
7969
                        for(int i=0; i<path.size()-1; i++)
 
7970
                        {
 
7971
                                SearchVertex sv1 = path.get(i);
 
7972
                                SearchVertex sv2 = path.get(i+1);
 
7973
                                sv1.last = sv2;
 
7974
                        }
 
7975
                        path.get(path.size()-1).last = null;
 
7976
                        SearchVertex result = path.get(0);
 
7977
                        result.wf = a;
 
7978
                        return result;
 
7979
                }
 
7980
                return null;
 
7981
        }
 
7982
 
5272
7983
        /********************************* MISCELLANEOUS SUPPORT *********************************/
5273
7984
 
5274
7985
        private double getMinWidth(List<PortInst> orderedPorts)
5322
8033
        }
5323
8034
 
5324
8035
        /**
 
8036
         * Method to determine the Euclidean distance between two via cuts.
 
8037
         * @param cut1LX via #1 low X.
 
8038
         * @param cut1HX via #1 high X.
 
8039
         * @param cut1LY via #1 low Y.
 
8040
         * @param cut1HY via #1 high Y.
 
8041
         * @param cut2LX via #2 low X.
 
8042
         * @param cut2HX via #2 high X.
 
8043
         * @param cut2LY via #2 low Y.
 
8044
         * @param cut2HY via #2 high Y.
 
8045
         * @return the corner-to-corner distance of the vias (0 if they touch or overlap).
 
8046
         */
 
8047
        private double cutDistance(double cut1LX, double cut1HX, double cut1LY, double cut1HY,
 
8048
                double cut2LX, double cut2HX, double cut2LY, double cut2HY)
 
8049
        {
 
8050
                if (cut1LX <= cut2HX && cut1HX >= cut2LX)
 
8051
                {
 
8052
                        if (cut1LY <= cut2HY && cut1HY >= cut2LY)
 
8053
                        {
 
8054
                                // contacts touch
 
8055
                                return 0;
 
8056
                        } else
 
8057
                        {
 
8058
                                // contacts are one above the other
 
8059
                                if ((cut1LY+cut1HY)/2 > (cut2LY+cut2HY)/2)
 
8060
                                        return cut1LY - cut2HY; else
 
8061
                                                return cut2LY - cut1HY;
 
8062
                        }
 
8063
                } else
 
8064
                {
 
8065
                        if (cut1LY <= cut2HY && cut1HY >= cut2LY)
 
8066
                        {
 
8067
                                // contacts are side-by-side
 
8068
                                if ((cut1LX+cut1HX)/2 > (cut2LX+cut2HX)/2)
 
8069
                                        return cut1LX - cut2HX; else
 
8070
                                                return cut2LX - cut1HX;
 
8071
                        }
 
8072
 
 
8073
                        // diagonal offset, compute Euclidean distance to corners
 
8074
                        double cut2CornerX, cut2CornerY, cut1CornerX, cut1CornerY;
 
8075
                        if ((cut2LX+cut2HX)/2 < (cut1LX+cut1HX)/2)
 
8076
                        {
 
8077
                                cut2CornerX = cut2HX;
 
8078
                                cut1CornerX = cut1LX;
 
8079
                        } else
 
8080
                        {
 
8081
                                cut2CornerX = cut2LX;
 
8082
                                cut1CornerX = cut1HX;
 
8083
                        }
 
8084
                        if ((cut2LY+cut2HY)/2 < (cut1LY+cut1HY)/2)
 
8085
                        {
 
8086
                                cut2CornerY = cut2HY;
 
8087
                                cut1CornerY = cut1LY;
 
8088
                        } else
 
8089
                        {
 
8090
                                cut2CornerY = cut2LY;
 
8091
                                cut1CornerY = cut1HY;
 
8092
                        }
 
8093
                        double dX = cut2CornerX - cut1CornerX, dY = cut2CornerY - cut1CornerY;
 
8094
                        return Math.sqrt(dX*dX + dY*dY);
 
8095
                }
 
8096
        }
 
8097
 
 
8098
        /**
5325
8099
         * Get the widest metal arc already connected to a given PortInst. Looks
5326
8100
         * recursively down the hierarchy.
5327
8101
         * @param pi the PortInst to connect.
5335
8109
                {
5336
8110
                        Connection c = it.next();
5337
8111
                        ArcInst ai = c.getArc();
 
8112
                        if (sogp.isPrevented(ai.getProto())) continue;
5338
8113
                        if (!ai.getProto().getFunction().isMetal()) continue;
5339
8114
                        double newWidth = ai.getLambdaBaseWidth();
5340
8115
                        if (newWidth > width) width = newWidth;
5352
8127
                return width;
5353
8128
        }
5354
8129
 
5355
 
        private boolean inValidPort(PortInst pi, NeededRoute nr)
5356
 
        {
5357
 
                ArcProto[] conns = getPossibleConnections(pi.getPortProto());
5358
 
                boolean valid = false;
5359
 
                for (int j = 0; j < conns.length; j++)
5360
 
                {
5361
 
                        ArcProto ap = conns[j];
5362
 
                        if (ap.getTechnology() != tech) continue;
5363
 
                        if (!ap.getFunction().isMetal()) continue;
5364
 
                        if (nr.preventArc(conns[j].getFunction().getLevel() - 1)) continue;
5365
 
                        valid = true;
5366
 
                        break;
5367
 
                }
5368
 
                if (!valid)
5369
 
                {
5370
 
                        warn("Cannot connect to port " + pi.getPortProto().getName() + " on node " +
5371
 
                                describe(pi.getNodeInst()) + " because all connecting layers have been prevented by Routing Preferences");
5372
 
                        return true;
5373
 
                }
5374
 
                return false;
5375
 
        }
5376
 
 
5377
8130
        /**
5378
8131
         * Class to cache a PortInst and its center location for Steiner Tree computation.
5379
8132
         */
5444
8197
                PrimitiveNode via;
5445
8198
                int orientation;
5446
8199
                int horMetal, verMetal;
 
8200
                int horMetalColor, verMetalColor;
5447
8201
                double horMetalInset, verMetalInset;
5448
8202
 
5449
 
                MetalVia(PrimitiveNode v, int o, int hm, double hmi, int vm, double vmi)
 
8203
                MetalVia(PrimitiveNode v, int o, int hm, int hmc, double hmi, int vm, int vmc, double vmi)
5450
8204
                {
5451
8205
                        via = v;
5452
8206
                        orientation = o;
5453
8207
                        horMetal = hm;
 
8208
                        horMetalColor = hmc;
5454
8209
                        horMetalInset = hmi;
5455
8210
                        verMetal = vm;
 
8211
                        verMetalColor = vmc;
5456
8212
                        verMetalInset = vmi;
5457
8213
                }
5458
8214
        }
5465
8221
        {
5466
8222
                List<MetalVia> vias = new ArrayList<MetalVia>();
5467
8223
 
5468
 
                void addVia(PrimitiveNode pn, int o, int hm, double hmi, int vm, double vmi)
 
8224
                void addVia(PrimitiveNode pn, int o, int hm, int hmc, double hmi, int vm, int vmc, double vmi)
5469
8225
                {
5470
 
                        vias.add(new MetalVia(pn, o, hm, hmi, vm, vmi));
 
8226
                        vias.add(new MetalVia(pn, o, hm, hmc, hmi, vm, vmc, vmi));
5471
8227
                        Collections.sort(vias, new PrimsBySize());
5472
8228
                }
5473
8229
 
5505
8261
                int total = 0;
5506
8262
                for(int i=0; i<numMetalLayers; i++)
5507
8263
                {
5508
 
                        BlockageTree bTree = rTrees.getMetalTree(metalLayers[i]);
 
8264
                        BlockageTree bTree = rTrees.getMetalTree(primaryMetalLayer[i]);
5509
8265
                        if (bTree.root != null)
5510
8266
                                total += getNumLeafs(bTree.root);
5511
8267
                }
5529
8285
                return total;
5530
8286
        }
5531
8287
 
 
8288
        Map<Layer,List<Rectangle2D>> removeGeometry;
 
8289
 
5532
8290
        /**
5533
8291
         * Method to build blockage R-Trees.
5534
8292
         * @param netList
5547
8305
                        Integer netNumber = netNumbers.get(net);
5548
8306
                        if (netNumber != null) continue;
5549
8307
 
5550
 
                        netNumbers.put(net, netNumber = Integer.valueOf(nextNetNumber.intValue() * 8));
 
8308
                        netNumbers.put(net, netNumber = Integer.valueOf(nextNetNumber.intValue() << SHIFTBLOCKBITS));
 
8309
                        if (RoutingDebug.isActive()) RoutingDebug.setNetName(netNumber, net.getName());
5551
8310
                        nextNetNumber.increment();
5552
8311
                        netIDs.put(net, netNumber);
5553
8312
                }
5555
8314
                // recursively add all polygons in the routing area
5556
8315
                setProgressNote("Find blockages...");
5557
8316
                setProgressValue(0, 100);
 
8317
                removeGeometry = new HashMap<Layer,List<Rectangle2D>>();
5558
8318
                boolean retval = addArea(cell, cellBounds, Orientation.IDENT.pureRotate(), true, nextNetNumber, linesInNonMahnattan);
 
8319
 
 
8320
                // add in additional user-specified blockages
 
8321
                List<SeaOfGatesExtraBlockage> list = sogp.getBlockages();
 
8322
                for(SeaOfGatesExtraBlockage sogeb : list)
 
8323
                {
 
8324
                        Rectangle2D bounds = new Rectangle2D.Double(sogeb.getLX(), sogeb.getLY(), sogeb.getHX()-sogeb.getLX(), sogeb.getHY()-sogeb.getLY());
 
8325
                        int metNo = sogeb.getLayer().getFunction().getLevel() - 1;
 
8326
                        Layer layer = primaryMetalLayer[metNo];
 
8327
                        Integer nn = Integer.valueOf((nextNetNumber.intValue() << SHIFTBLOCKBITS) | BLOCKAGEFAKEUSERSUPPLIED);
 
8328
                        nextNetNumber.increment();
 
8329
                        MutableInteger netID = new MutableInteger(nn.intValue());
 
8330
                        addRectangle(bounds, layer, netID, false, false);
 
8331
                }
 
8332
 
 
8333
                // now remove any geometry that was covered by a removal layer
 
8334
                for(Layer metLayer : removeGeometry.keySet())
 
8335
                {
 
8336
                        List<Rectangle2D> removeRects = removeGeometry.get(metLayer);
 
8337
                        for(Rectangle2D rect : removeRects)
 
8338
                        {
 
8339
                                int metNum = metLayer.getFunction().getLevel() - 1;
 
8340
                                int metCol = metLayer.getFunction().getMaskColor();
 
8341
                                Layer primaryMetLayer = primaryMetalLayer[metNum];
 
8342
                                BlockageTree bTree = rTrees.getMetalTree(primaryMetLayer);
 
8343
                                List<SOGBound> thingsThatGetRemoved = new ArrayList<SOGBound>();
 
8344
                                for (Iterator<SOGBound> sea = bTree.search(rect); sea.hasNext();)
 
8345
                                {
 
8346
                                        SOGBound sBound = sea.next();
 
8347
                                        if (sBound.maskLayer != metCol) continue;
 
8348
                                        Rectangle2D bound = sBound.getBounds();
 
8349
                                        if (bound.getMaxX() <= rect.getMinX() || bound.getMinX() >= rect.getMaxX() ||
 
8350
                                                bound.getMaxY() <= rect.getMinY() || bound.getMinY() >= rect.getMaxY()) continue;
 
8351
                                        thingsThatGetRemoved.add(sBound);
 
8352
                                }
 
8353
 
 
8354
                                // remove those R-Tree elements that get cut
 
8355
                                RTNode<SOGBound> rootFixp = bTree.getRoot();
 
8356
                                for(SOGBound s : thingsThatGetRemoved)
 
8357
                                {
 
8358
                                        RTNode<SOGBound> newRootFixp = RTNode.unLinkGeom(null, rootFixp, s);
 
8359
                                        if (newRootFixp != rootFixp) bTree.setRoot(rootFixp = newRootFixp);
 
8360
                                }
 
8361
 
 
8362
                                // now reinsert geometry that wasn't removed
 
8363
                                for(SOGBound s : thingsThatGetRemoved)
 
8364
                                {
 
8365
                                        PolyMerge merge = new PolyMerge();
 
8366
                                        merge.addRectangle(metLayer, s.bound);
 
8367
                                        merge.subtract(metLayer, new Poly(rect));
 
8368
                                        List<PolyBase> remaining = merge.getMergedPoints(metLayer, true);
 
8369
                                        for(PolyBase pb : remaining)
 
8370
                                        {
 
8371
                                                ERectangle reducedBound = ERectangle.fromLambda(pb.getBounds2D());
 
8372
                                                SOGBound sogb = new SOGBound(reducedBound, s.getNetID(), s.maskLayer);
 
8373
                                                RTNode<SOGBound> newRootFixp = RTNode.linkGeom(null, rootFixp, sogb);
 
8374
                                                if (newRootFixp != rootFixp) bTree.setRoot(rootFixp = newRootFixp);
 
8375
                                        }
 
8376
                                }
 
8377
                        }
 
8378
                }
5559
8379
                return retval;
5560
8380
        }
5561
8381
 
5570
8390
         * @return true if some of the geometry is nonmanhattan (and may cause problems)
5571
8391
         */
5572
8392
        private boolean addArea(Cell cell, Rectangle2D bounds, FixpTransform transToTop, boolean topLevel,
5573
 
                        MutableInteger nextNetNumber, List<EPoint> linesInNonMahnattan)
 
8393
                MutableInteger nextNetNumber, List<EPoint> linesInNonMahnattan)
5574
8394
        {
5575
8395
                // first add primitive nodes and arcs
5576
8396
                boolean hasNonmanhattan = false;
5582
8402
                        {
5583
8403
                                NodeInst ni = (NodeInst)geom;
5584
8404
                                if (ni.isCellInstance()) { numCells++;   continue; }
 
8405
                                PrimitiveNode pNp = (PrimitiveNode)ni.getProto();
 
8406
                                if (pNp.getFunction() == PrimitiveNode.Function.PIN) continue;
5585
8407
                                FixpTransform nodeTrans = ni.rotateOut(transToTop);
5586
 
                                PrimitiveNode pNp = (PrimitiveNode)ni.getProto();
5587
8408
                                Technology tech = pNp.getTechnology();
5588
8409
                                Poly[] nodeInstPolyList = tech.getShapeOfNode(ni, true, false, null);
5589
8410
                                MutableInteger netNumber = null;
5590
8411
                                List<Integer> exclusionLayers = null;
5591
8412
                                if (pNp == Generic.tech().routeNode)
5592
8413
                                {
5593
 
                                        Integer nn = Integer.valueOf(nextNetNumber.intValue() * 8);
 
8414
                                        Integer nn = Integer.valueOf(nextNetNumber.intValue() << SHIFTBLOCKBITS);
5594
8415
                                        nextNetNumber.increment();
5595
8416
                                        netNumber = new MutableInteger(nn.intValue());
5596
8417
                                        exclusionLayers = parseExclusionLayers(ni);
5602
8423
                                        {
5603
8424
                                                for(Integer lay : exclusionLayers)
5604
8425
                                                {
5605
 
                                                        poly.setLayer(getMetalLayer(lay.intValue()));
 
8426
                                                        poly.setLayer(primaryMetalLayer[lay.intValue()]);
5606
8427
                                                        if (addLayer(poly, nodeTrans, netNumber, false, linesInNonMahnattan, true)) hasNonmanhattan = true;
5607
8428
                                                }
5608
8429
                                        } else
5638
8459
                                        {
5639
8460
                                                cellCount++;
5640
8461
                                                setProgressValue(cellCount, numCells+1);
5641
 
                                                setProgressNote("Find blockages in " + ni.describe(false) + "...");
5642
8462
                                        }
5643
8463
                                        Rectangle2D subBounds = new Rectangle2D.Double(bounds.getMinX(), bounds.getMinY(),
5644
8464
                                                bounds.getWidth(), bounds.getHeight());
5724
8544
         * @return true if the geometry is nonmanhattan (and may cause problems).
5725
8545
         */
5726
8546
        private boolean addLayer(PolyBase poly, FixpTransform trans, MutableInteger netID,
5727
 
                        boolean lockTree, List<EPoint> linesInNonMahnattan, boolean merge)
 
8547
                boolean lockTree, List<EPoint> linesInNonMahnattan, boolean merge)
5728
8548
        {
5729
8549
                boolean isNonmanhattan = false;
5730
8550
                Layer layer = poly.getLayer();
5731
8551
                Layer.Function fun = layer.getFunction();
 
8552
 
 
8553
                // save any removal geometry
 
8554
                Layer removeAp = removeLayers.get(layer);
 
8555
                if (removeAp != null)
 
8556
                {
 
8557
                        List<Rectangle2D> geomsToRemove = removeGeometry.get(removeAp);
 
8558
                        if (geomsToRemove == null) removeGeometry.put(removeAp, geomsToRemove = new ArrayList<Rectangle2D>());
 
8559
                        poly.transform(trans);
 
8560
                        Rectangle2D bounds = poly.getBox();
 
8561
                        if (bounds == null) return true;
 
8562
                        geomsToRemove.add(bounds);
 
8563
                        return false;
 
8564
                }
 
8565
 
5732
8566
                if (fun.isMetal())
5733
8567
                {
5734
 
                        // ignore polygons that aren't solid filled areas                               TODO: debug
 
8568
                        // ignore polygons that aren't solid filled areas
5735
8569
                        if (poly.getStyle() != Poly.Type.FILLED) return false;
5736
8570
                        poly.transform(trans);
5737
8571
                        Rectangle2D bounds = poly.getBox();
5738
8572
                        if (bounds == null)
5739
8573
                        {
5740
8574
                                addPolygon(poly, layer, netID, lockTree);
5741
 
                                for (Point p : poly.getPoints())
5742
 
                                        linesInNonMahnattan.add(EPoint.fromLambda(p.getX(), p.getY()));
5743
 
                                isNonmanhattan = true;
 
8575
                                Point[] points = poly.getPoints();
 
8576
                                for (int i=1; i<points.length; i++)
 
8577
                                {
 
8578
                                        if (points[i-1].getX() != points[i].getX() && points[i-1].getY() != points[i].getY())
 
8579
                                        {
 
8580
                                                isNonmanhattan = true;
 
8581
                                                linesInNonMahnattan.add(EPoint.fromLambda(points[i-1].getX(), points[i-1].getY()));
 
8582
                                                linesInNonMahnattan.add(EPoint.fromLambda(points[i].getX(), points[i].getY()));
 
8583
                                        }
 
8584
                                }
5744
8585
                        } else
5745
8586
                        {
5746
8587
                                addRectangle(bounds, layer, netID, lockTree, merge);
5749
8590
                {
5750
8591
                        Rectangle2D bounds = poly.getBounds2D();
5751
8592
                        DBMath.transformRect(bounds, trans);
5752
 
                        addVia(EPoint.fromLambda(bounds.getCenterX(), bounds.getCenterY()), layer, netID, lockTree);
 
8593
                        addVia(ERectangle.fromLambda(bounds), layer, netID, lockTree);
5753
8594
                }
5754
8595
                return isNonmanhattan;
5755
8596
        }
5756
8597
 
 
8598
        public static String describeMetal(int metal, int color)
 
8599
        {
 
8600
                String ret = "M" + (metal+1);
 
8601
                if (color > 0) ret += (char)('a' + color - 1);
 
8602
                return ret;
 
8603
        }
 
8604
 
5757
8605
        /**
5758
8606
         * Method to add a rectangle to the metal R-Tree.
5759
8607
         * @param bounds the rectangle to add.
5773
8621
                        for (Iterator<SOGBound> sea = bTree.search(bounds); sea.hasNext(); )
5774
8622
                        {
5775
8623
                                SOGBound sBound = sea.next();
 
8624
                                if (sBound instanceof SOGPoly) continue;
5776
8625
 
5777
8626
                                // if an existing bound is bigger than new one, ignore this
5778
8627
                                if (sBound.bound.getMinX() <= bounds.getMinX() &&
5806
8655
                                }
5807
8656
                        }
5808
8657
                }
5809
 
                
 
8658
 
5810
8659
                if (lockTree) bTree.lock();
5811
8660
                try {
5812
 
                        sogb = new SOGBound(ERectangle.fromLambda(bounds), netID);
 
8661
                        int maskLayer = layer.getFunction().getMaskColor();
 
8662
                        sogb = new SOGBound(ERectangle.fromLambda(bounds), netID, maskLayer);
5813
8663
                        RTNode<SOGBound> rootFixp = bTree.getRoot();
5814
8664
                        if (rootFixp == null)
5815
8665
                        {
5836
8686
                BlockageTree bTree = rTrees.getMetalTree(layer);
5837
8687
                if (lockTree) bTree.lock();
5838
8688
                try {
5839
 
                        SOGBound sogb = new SOGPoly(ERectangle.fromLambda(poly.getBounds2D()), netID, poly);
 
8689
                        int maskLayer = layer.getFunction().getMaskColor();
 
8690
                        SOGBound sogb = new SOGPoly(ERectangle.fromLambda(poly.getBounds2D()), netID, poly, maskLayer);
5840
8691
                        RTNode<SOGBound> rootFixp = bTree.getRoot();
5841
8692
                        if (rootFixp == null)
5842
8693
                        {
5857
8708
         * @param netID the global network ID of the geometry.
5858
8709
         * @param lockTree true to lock the R-Tree before accessing it (when doing parallel routing).
5859
8710
         */
5860
 
        private void addVia(EPoint loc, Layer layer, MutableInteger netID, boolean lockTree)
 
8711
        private void addVia(ERectangle rect, Layer layer, MutableInteger netID, boolean lockTree)
5861
8712
        {
5862
8713
                BlockageTree bTree = rTrees.getViaTree(layer);
5863
8714
                if (lockTree) bTree.lock();
5864
8715
                try {
5865
 
                        SOGBound sogb = new SOGVia(loc, netID);
 
8716
                        SOGBound sogb = new SOGVia(rect, netID);
5866
8717
                        RTNode<SOGBound> rootFixp = bTree.getRoot();
5867
8718
                        if (rootFixp == null)
5868
8719
                        {
5905
8756
                }
5906
8757
        }
5907
8758
 
5908
 
        private static class BlockageTrees
 
8759
        private class BlockageTrees
5909
8760
        {
5910
 
                private final BlockageTree[] metalTrees;
 
8761
//              private final BlockageTree[][] metalTrees;                      // TODO: trees for every mask color
 
8762
                private final BlockageTree[] metalTrees;                        // trees ignore mask color
 
8763
 
5911
8764
                private final BlockageTree[] viaTrees;
5912
8765
 
5913
8766
                BlockageTrees(int numMetals)
5914
8767
                {
5915
 
                        metalTrees = new BlockageTree[numMetals];
 
8768
//                      metalTrees = new BlockageTree[numMetals][];             // TODO: trees for every mask color
 
8769
                        metalTrees = new BlockageTree[numMetals];               // trees ignore mask color
 
8770
 
5916
8771
                        viaTrees = new BlockageTree[numMetals];
5917
 
                        for (int i = 0; i < metalTrees.length; i++) {
5918
 
                                metalTrees[i] = new BlockageTree(null);
 
8772
                        for (int i = 0; i < metalTrees.length; i++)
 
8773
                        {
 
8774
//                              metalTrees[i] = new BlockageTree[metalArcs[i].length];          // TODO: trees for every mask color
 
8775
//                              for(int c=0; c<metalArcs[i].length; c++)
 
8776
//                                      metalTrees[i][c] = new BlockageTree(null);
 
8777
                                metalTrees[i] = new BlockageTree(null);                                         // trees ignore mask color
 
8778
 
5919
8779
                                viaTrees[i] = new BlockageTree(null);
5920
8780
                        }
5921
8781
                }
5985
8845
                {
5986
8846
                        int netValue = 0;
5987
8847
                        if (netID != null) netValue = netID.intValue();
5988
 
                        if ((netValue & 0xFFFFFFF8) == (otherNetID.intValue() & 0xFFFFFFF8)) return true;
 
8848
                        if ((netValue >> SHIFTBLOCKBITS) == (otherNetID.intValue() >> SHIFTBLOCKBITS)) return true;
5989
8849
                        return false;
5990
8850
                }
5991
8851
 
5997
8857
                public boolean isPseudoBlockage()
5998
8858
                {
5999
8859
                        if (netID == null) return false;
6000
 
                        return (netID.intValue() & 1) != 0;
 
8860
                        return (netID.intValue() & BLOCKAGEFAKEENDPOINT) != 0;
6001
8861
                }
6002
8862
 
6003
8863
                /**
6004
 
                 * Method to tell whether the network ID on this object has a specific "route end" bit.
6005
 
                 * @param bit either 2 or 4, depending on the end of the route being requested.
6006
 
                 * @return true if this network ID has the specified "route end" bit.
 
8864
                 * Method to tell whether the network ID on this object is a
 
8865
                 * user-supplied blockage.
 
8866
                 * @return true if this is user-supplied blockage.
6007
8867
                 */
6008
 
                public boolean hasEndBit(int bit)
 
8868
                public boolean isUserSuppliedBlockage()
6009
8869
                {
6010
8870
                        if (netID == null) return false;
6011
 
                        return (netID.intValue() & bit) != 0;
 
8871
                        return (netID.intValue() & BLOCKAGEFAKEUSERSUPPLIED) != 0;
6012
8872
                }
6013
8873
        }
6014
8874
 
6018
8878
        public static class SOGBound extends SOGNetID implements RTBounds
6019
8879
        {
6020
8880
                private ERectangle bound;
 
8881
                private int maskLayer;
6021
8882
 
6022
 
                SOGBound(ERectangle bound, MutableInteger netID)
 
8883
                SOGBound(ERectangle bound, MutableInteger netID, int maskLayer)
6023
8884
                {
6024
8885
                        super(netID);
6025
8886
                        this.bound = bound;
 
8887
                        this.maskLayer = maskLayer;
6026
8888
                }
6027
8889
 
6028
8890
                @Override
6029
8891
                public ERectangle getBounds() { return bound; }
6030
8892
 
 
8893
                public boolean containsPoint(double x, double y)
 
8894
                {
 
8895
                        return x >= bound.getMinX() && x <= bound.getMaxX() && y >= bound.getMinY() && y <= bound.getMaxY();
 
8896
                }
 
8897
 
 
8898
                public boolean isManhattan() { return true; }
 
8899
 
6031
8900
                @Override
6032
8901
                public String toString() { return "SOGBound on net " + getNetID(); }
6033
8902
        }
6034
8903
 
6035
 
        private static class SOGPoly extends SOGBound
 
8904
        public static class SOGPoly extends SOGBound
6036
8905
        {
6037
8906
                private PolyBase poly;
6038
8907
 
6039
 
                SOGPoly(ERectangle bound, MutableInteger netID, PolyBase poly)
 
8908
                SOGPoly(ERectangle bound, MutableInteger netID, PolyBase poly, int maskLayer)
6040
8909
                {
6041
 
                        super(bound, netID);
 
8910
                        super(bound, netID, maskLayer);
6042
8911
                        this.poly = poly;
6043
8912
                }
6044
8913
 
 
8914
                public boolean containsPoint(double x, double y)
 
8915
                {
 
8916
                        return poly.isInside(new Point2D.Double(x, y));
 
8917
                }
 
8918
 
 
8919
                public boolean isManhattan()
 
8920
                {
 
8921
                        Point[] pts = poly.getPoints();
 
8922
                        for(int i=1; i<pts.length; i++)
 
8923
                        {
 
8924
                                if (pts[i].getX() != pts[i-1].getX() && pts[i].getY() != pts[i-1].getY()) return false;
 
8925
                        }
 
8926
                        return true;
 
8927
                }
 
8928
 
6045
8929
                public PolyBase getPoly() { return poly; }
6046
8930
        }
6047
8931
 
6050
8934
         */
6051
8935
        public static class SOGVia extends SOGBound
6052
8936
        {
6053
 
                private EPoint loc;
6054
 
 
6055
 
                SOGVia(EPoint loc, MutableInteger netID)
 
8937
                SOGVia(ERectangle rect, MutableInteger netID)
6056
8938
                {
6057
 
                        super(ERectangle.fromFixp(loc.getFixpX(), loc.getFixpY(), 0, 0), netID);
6058
 
                        this.loc = loc;
 
8939
                        super(rect, netID, 0);
6059
8940
                }
6060
8941
 
6061
8942
                @Override
6241
9122
                                }
6242
9123
                        }
6243
9124
                }
6244
 
        };
 
9125
        }
6245
9126
 
6246
9127
        public static class GRBucket implements Comparable<GRBucket>
6247
9128
        {
6275
9156
                public String toString() { return "BUCKET-" + id; }
6276
9157
 
6277
9158
                public int compareTo(GRBucket other) { return id - other.id; }
6278
 
        };
 
9159
        }
6279
9160
 
6280
9161
        public static class GRNet
6281
9162
        {
6289
9170
                public void addWire(GRWire w) { wires.add(w); }
6290
9171
 
6291
9172
                public List<GRWire> getWires() { return wires; }
6292
 
        };
 
9173
        }
6293
9174
 
6294
9175
        public static class GRWire
6295
9176
        {
6410
9291
                        }
6411
9292
                        return false;
6412
9293
                }
6413
 
        };
 
9294
        }
6414
9295
 
6415
9296
        private static class GREdge
6416
9297
        {
6442
9323
                        double ratio = current / (double)capacity;
6443
9324
                        return minCost + (maxCost - minCost) * ratio;
6444
9325
                }
6445
 
        };
 
9326
        }
6446
9327
 
6447
9328
        private static class GRPathElement
6448
9329
        {
6458
9339
                public GRBucket getBucket() { return n; }
6459
9340
 
6460
9341
                public GREdge getEdge() { return e; }
6461
 
        };
 
9342
        }
6462
9343
 
6463
9344
        private static class GRWavefrontPoint implements Comparable<GRWavefrontPoint>
6464
9345
        {
6481
9362
                        if (cost > other.cost) return 1000000000;
6482
9363
                        return n.compareTo(other.n);
6483
9364
                }
6484
 
        };
6485
 
 
 
9365
        }
6486
9366
}