pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00060 #define NET_HEAP 1 00061 #ifdef HAVE_CONFIG_H 00062 #include "config.h" 00063 #endif 00064 00065 #include "global.h" 00066 00067 #include <assert.h> 00068 #include <setjmp.h> 00069 00070 #include "data.h" 00071 #include "macro.h" 00072 #include "autoroute.h" 00073 #include "box.h" 00074 #include "create.h" 00075 #include "draw.h" 00076 #include "error.h" 00077 #include "find.h" 00078 #include "heap.h" 00079 #include "rtree.h" 00080 #include "misc.h" 00081 #include "mtspace.h" 00082 #include "mymem.h" 00083 #include "polygon.h" 00084 #include "rats.h" 00085 #include "remove.h" 00086 #include "thermal.h" 00087 #include "undo.h" 00088 #include "vector.h" 00089 #include "pcb-printf.h" 00090 #include "hid_draw.h" 00091 00092 #ifdef HAVE_LIBDMALLOC 00093 #include <dmalloc.h> 00094 #endif 00095 00096 /* #defines to enable some debugging output */ 00097 /* 00098 #define ROUTE_VERBOSE 00099 */ 00100 00101 /* 00102 #define ROUTE_DEBUG 00103 //#define DEBUG_SHOW_ROUTE_BOXES 00104 #define DEBUG_SHOW_EXPANSION_BOXES 00105 //#define DEBUG_SHOW_EDGES 00106 //#define DEBUG_SHOW_VIA_BOXES 00107 #define DEBUG_SHOW_TARGETS 00108 #define DEBUG_SHOW_SOURCES 00109 //#define DEBUG_SHOW_ZIGZAG 00110 */ 00111 00112 static direction_t 00113 directionIncrement(direction_t dir) 00114 { 00115 switch(dir) 00116 { 00117 case NORTH: 00118 dir = EAST; 00119 break; 00120 case EAST: 00121 dir = SOUTH; 00122 break; 00123 case SOUTH: 00124 dir = WEST; 00125 break; 00126 case WEST: 00127 dir = NE; 00128 break; 00129 case NE: 00130 dir = SE; 00131 break; 00132 case SE: 00133 dir = SW; 00134 break; 00135 case SW: 00136 dir = NW; 00137 break; 00138 case NW: 00139 dir = ALL; 00140 break; 00141 case ALL: 00142 dir = NORTH; 00143 break; 00144 } 00145 return dir; 00146 } 00147 00148 #ifdef ROUTE_DEBUG 00149 HID_DRAW *ddraw = NULL; 00150 static hidGC ar_gc = 0; 00151 #endif 00152 00153 #define EXPENSIVE 3e28 00154 /* round up "half" thicknesses */ 00155 #define HALF_THICK(x) (((x)+1)/2) 00156 /* a styles maximum bloat is its keepaway plus the larger of its via radius 00157 * or line half-thickness. */ 00158 #define BLOAT(style)\ 00159 ((style)->Keepaway + HALF_THICK((style)->Thick)) 00160 /* conflict penalty is less for traces laid down during previous pass than 00161 * it is for traces already laid down in this pass. */ 00162 #define CONFLICT_LEVEL(rb)\ 00163 (((rb)->flags.is_odd==AutoRouteParameters.is_odd) ?\ 00164 HI_CONFLICT : LO_CONFLICT ) 00165 #define CONFLICT_PENALTY(rb)\ 00166 ((CONFLICT_LEVEL(rb)==HI_CONFLICT ? \ 00167 AutoRouteParameters.ConflictPenalty : \ 00168 CONFLICT_LEVEL(rb)==LO_CONFLICT ? \ 00169 AutoRouteParameters.LastConflictPenalty : 1) * (rb)->pass) 00170 00171 #define _NORTH 1 00172 #define _EAST 2 00173 #define _SOUTH 4 00174 #define _WEST 8 00175 00176 #define LIST_LOOP(init, which, x) do {\ 00177 routebox_t *__next_one__ = (init);\ 00178 x = NULL;\ 00179 if (!__next_one__)\ 00180 assert(__next_one__);\ 00181 else\ 00182 while (!x || __next_one__ != (init)) {\ 00183 x = __next_one__;\ 00184 /* save next one first in case the command modifies or frees it */\ 00185 __next_one__ = x->which.next 00186 #define FOREACH_SUBNET(net, p) do {\ 00187 routebox_t *_pp_;\ 00188 /* fail-fast: check subnet_processed flags */\ 00189 LIST_LOOP(net, same_net, p); \ 00190 assert(!p->flags.subnet_processed);\ 00191 END_LOOP;\ 00192 /* iterate through *distinct* subnets */\ 00193 LIST_LOOP(net, same_net, p); \ 00194 if (!p->flags.subnet_processed) {\ 00195 LIST_LOOP(p, same_subnet, _pp_);\ 00196 _pp_->flags.subnet_processed=1;\ 00197 END_LOOP 00198 #define END_FOREACH(net, p) \ 00199 }; \ 00200 END_LOOP;\ 00201 /* reset subnet_processed flags */\ 00202 LIST_LOOP(net, same_net, p); \ 00203 p->flags.subnet_processed=0;\ 00204 END_LOOP;\ 00205 } while (0) 00206 #define SWAP(t, f, s) do { t a=s; s=f; f=a; } while (0) 00207 /* notes: 00208 * all rectangles are assumed to be closed on the top and left and 00209 * open on the bottom and right. That is, they include their top-left 00210 * corner but don't include their bottom and right edges. 00211 * 00212 * expansion regions are always half-closed. This means that when 00213 * tracing paths, you must steer clear of the bottom and right edges., 00214 * because these are not actually in the allowed box. 00215 * 00216 * All routeboxes *except* EXPANSION_AREAS now have their "box" bloated by 00217 * their particular required keepaway. This simplifies the tree searching. 00218 * the "sbox" contains the unbloated box. 00219 */ 00220 /* --------------------------------------------------------------------------- 00221 * some local types 00222 */ 00223 00224 /* enumerated type for conflict levels */ 00225 typedef enum 00226 { NO_CONFLICT = 0, LO_CONFLICT = 1, HI_CONFLICT = 2 } 00227 conflict_t; 00228 00229 typedef struct routebox_list 00230 { 00231 struct routebox *next, *prev; 00232 }routebox_list; 00233 00234 typedef enum etype 00235 { PAD, PIN, VIA, VIA_SHADOW, LINE, OTHER, EXPANSION_AREA, PLANE, THERMAL } 00236 etype; 00237 00238 typedef struct routebox 00239 { 00240 BoxType box, sbox; 00241 union 00242 { 00243 PadType *pad; 00244 PinType *pin; 00245 PinType *via; 00246 struct routebox *via_shadow; /* points to the via in r-tree which 00247 * points to the PinType in the PCB. */ 00248 LineType *line; 00249 void *generic; /* 'other' is polygon, arc, text */ 00250 struct routebox *expansion_area; /* previous expansion area in search */ 00251 } 00252 parent; 00253 unsigned short group; 00254 unsigned short layer; 00255 etype type; 00256 struct 00257 { 00258 unsigned nonstraight:1; 00259 unsigned fixed:1; 00260 /* for searches */ 00261 unsigned source:1; 00262 unsigned target:1; 00263 /* rects on same net as source and target don't need clearance areas */ 00264 unsigned nobloat:1; 00265 /* mark circular pins, so that we be sure to connect them up properly */ 00266 unsigned circular:1; 00267 /* we sometimes create routeboxen that don't actually belong to a 00268 * r-tree yet -- make sure refcount of homelesss is set properly */ 00269 unsigned homeless:1; 00270 /* was this nonfixed obstacle generated on an odd or even pass? */ 00271 unsigned is_odd:1; 00272 /* fixed route boxes that have already been "routed through" in this 00273 * search have their "touched" flag set. */ 00274 unsigned touched:1; 00275 /* this is a status bit for iterating through *different* subnets */ 00276 unsigned subnet_processed:1; 00277 /* some expansion_areas represent via candidates */ 00278 unsigned is_via:1; 00279 /* mark non-straight lines which go from bottom-left to upper-right, 00280 * instead of from upper-left to bottom-right. */ 00281 unsigned bl_to_ur:1; 00282 /* mark polygons which are "transparent" for via-placement; that is, 00283 * vias through the polygon will automatically be given a keepaway 00284 * and will not electrically connect to the polygon. */ 00285 unsigned clear_poly:1; 00286 /* this marks "conflicting" routes that must be torn up to obtain 00287 * a correct routing. This flag allows us to return a correct routing 00288 * even if the user cancels auto-route after a non-final pass. */ 00289 unsigned is_bad:1; 00290 /* for assertion that 'box' is never changed after creation */ 00291 unsigned inited:1; 00292 /* indicate this expansion ares is a thermal between the pin and plane */ 00293 unsigned is_thermal; 00294 } 00295 flags; 00296 /* indicate the direction an expansion box came from */ 00297 cost_t cost; 00298 CheapPointType cost_point; 00299 /* reference count for homeless routeboxes; free when refcount==0 */ 00300 int refcount; 00301 /* when routing with conflicts, we keep a record of what we're 00302 * conflicting with. 00303 */ 00304 vector_t *conflicts_with; 00305 /* route style of the net associated with this routebox */ 00306 RouteStyleType *style; 00307 /* congestion values for the edges of an expansion box */ 00308 unsigned char n, e, s, w; 00309 /* what pass this this track was laid down on */ 00310 unsigned char pass; 00311 /* the direction this came from, if any */ 00312 direction_t came_from; 00313 /* circular lists with connectivity information. */ 00314 routebox_list same_net, same_subnet, original_subnet, different_net; 00315 union { 00316 PinType *via; 00317 LineType *line; 00318 } livedraw_obj; 00319 } 00320 routebox_t; 00321 00322 typedef struct routedata 00323 { 00324 /* one rtree per layer *group */ 00325 rtree_t *layergrouptree[MAX_GROUP]; /* no silkscreen layers here =) */ 00326 /* root pointer into connectivity information */ 00327 routebox_t *first_net; 00328 /* default routing style */ 00329 RouteStyleType defaultstyle; 00330 /* style structures */ 00331 RouteStyleType *styles[NUM_STYLES + 1]; 00332 /* what is the maximum bloat (keepaway+line half-width or 00333 * keepaway+via_radius) for any style we've seen? */ 00334 Coord max_bloat; 00335 Coord max_keep; 00336 mtspace_t *mtspace; 00337 } 00338 routedata_t; 00339 00340 typedef struct edge_struct 00341 { 00342 routebox_t *rb; /* path expansion edges are real routeboxen. */ 00343 CheapPointType cost_point; 00344 cost_t cost_to_point; /* from source */ 00345 cost_t cost; /* cached edge cost */ 00346 routebox_t *mincost_target; /* minimum cost from cost_point to any target */ 00347 vetting_t *work; /* for via search edges */ 00348 direction_t expand_dir; 00349 struct 00350 { 00351 /* this indicates that this 'edge' is a via candidate. */ 00352 unsigned is_via:1; 00353 /* record "conflict level" of via candidates, in case we need to split 00354 * them later. */ 00355 conflict_t via_conflict_level:2; 00356 /* when "routing with conflicts", sometimes edge is interior. */ 00357 unsigned is_interior:1; 00358 /* this is a fake edge used to defer searching for via spaces */ 00359 unsigned via_search:1; 00360 /* this is a via edge in a plane where the cost point moves for free */ 00361 unsigned in_plane:1; 00362 } 00363 flags; 00364 } 00365 edge_t; 00366 00367 static struct 00368 { 00369 /* net style parameters */ 00370 RouteStyleType *style; 00371 /* the present bloat */ 00372 Coord bloat; 00373 /* cost parameters */ 00374 cost_t ViaCost, /* additional "length" cost for using a via */ 00375 LastConflictPenalty, /* length mult. for routing over last pass' trace */ 00376 ConflictPenalty, /* length multiplier for routing over another trace */ 00377 JogPenalty, /* additional "length" cost for changing direction */ 00378 CongestionPenalty, /* (rational) length multiplier for routing in */ 00379 NewLayerPenalty, /* penalty for routing on a previously unused layer */ 00380 MinPenalty; /* smallest Direction Penalty */ 00381 /* maximum conflict incidence before calling it "no path found" */ 00382 int hi_conflict; 00383 /* are vias allowed? */ 00384 bool use_vias; 00385 /* is this an odd or even pass? */ 00386 bool is_odd; 00387 /* permit conflicts? */ 00388 bool with_conflicts; 00389 /* is this a final "smoothing" pass? */ 00390 bool is_smoothing; 00391 /* rip up nets regardless of conflicts? */ 00392 bool rip_always; 00393 bool last_smooth; 00394 unsigned char pass; 00395 } 00396 AutoRouteParameters; 00397 00398 struct routeone_state 00399 { 00400 /* heap of all candidate expansion edges */ 00401 heap_t *workheap; 00402 /* information about the best path found so far. */ 00403 routebox_t *best_path, *best_target; 00404 cost_t best_cost; 00405 }; 00406 00407 00408 /* --------------------------------------------------------------------------- 00409 * some local prototypes 00410 */ 00411 static routebox_t *CreateExpansionArea (const BoxType * area, Cardinal group, 00412 routebox_t * parent, 00413 bool relax_edge_requirements, 00414 edge_t * edge); 00415 00416 static cost_t edge_cost (const edge_t * e, const cost_t too_big); 00417 static void best_path_candidate (struct routeone_state *s, 00418 edge_t * e, routebox_t * best_target); 00419 00420 static BoxType edge_to_box (const routebox_t * rb, direction_t expand_dir); 00421 00422 static void add_or_destroy_edge (struct routeone_state *s, edge_t * e); 00423 00424 static void 00425 RD_DrawThermal (routedata_t * rd, Coord X, Coord Y, 00426 Cardinal group, Cardinal layer, routebox_t * subnet, 00427 bool is_bad); 00428 static void ResetSubnet (routebox_t * net); 00429 #ifdef ROUTE_DEBUG 00430 static int showboxen = -2; 00431 static int aabort = 0; 00432 static void showroutebox (routebox_t * rb); 00433 #endif 00434 00435 /* --------------------------------------------------------------------------- 00436 * some local identifiers 00437 */ 00438 /* group number of groups that hold surface mount pads */ 00439 static Cardinal front, back; 00440 static bool usedGroup[MAX_GROUP]; 00441 static int x_cost[MAX_GROUP], y_cost[MAX_GROUP]; 00442 static bool is_layer_group_active[MAX_GROUP]; 00443 static int ro = 0; 00444 static int smoothes = 1; 00445 static int passes = 12; 00446 static int routing_layers = 0; 00447 static float total_wire_length = 0; 00448 static int total_via_count = 0; 00449 00450 /* assertion helper for routeboxen */ 00451 #ifndef NDEBUG 00452 static int 00453 __routebox_is_good (routebox_t * rb) 00454 { 00455 assert (rb && (rb->group < max_group) && 00456 (rb->box.X1 <= rb->box.X2) && (rb->box.Y1 <= rb->box.Y2) && 00457 (rb->flags.homeless ? 00458 (rb->box.X1 != rb->box.X2) || (rb->box.Y1 != rb->box.Y2) : 00459 (rb->box.X1 != rb->box.X2) && (rb->box.Y1 != rb->box.Y2))); 00460 assert ((rb->flags.source ? rb->flags.nobloat : 1) && 00461 (rb->flags.target ? rb->flags.nobloat : 1) && 00462 (rb->flags.homeless ? !rb->flags.touched : rb->refcount == 0) && 00463 (rb->flags.touched ? rb->type != EXPANSION_AREA : 1)); 00464 assert ((rb->flags.is_odd ? (!rb->flags.fixed) && 00465 (rb->type == VIA || rb->type == VIA_SHADOW || rb->type == LINE 00466 || rb->type == PLANE) : 1)); 00467 assert (rb->flags.clear_poly ? 00468 ((rb->type == OTHER || rb->type == PLANE) && rb->flags.fixed 00469 && !rb->flags.homeless) : 1); 00470 assert (rb->flags.inited); 00471 /* run through conflict list showing none are homeless, targets or sources */ 00472 if (rb->conflicts_with) 00473 { 00474 int i; 00475 for (i = 0; i < vector_size (rb->conflicts_with); i++) 00476 { 00477 routebox_t *c = vector_element (rb->conflicts_with, i); 00478 assert (!c->flags.homeless && !c->flags.source && !c->flags.target 00479 && !c->flags.fixed); 00480 } 00481 } 00482 assert (rb->style != NULL && rb->style != NULL); 00483 assert (rb->type == EXPANSION_AREA 00484 || (rb->same_net.next && rb->same_net.prev && rb->same_subnet.next 00485 && rb->same_subnet.prev && rb->original_subnet.next 00486 && rb->original_subnet.prev && rb->different_net.next 00487 && rb->different_net.prev)); 00488 return 1; 00489 } 00490 static int 00491 __edge_is_good (edge_t * e) 00492 { 00493 assert (e && e->rb && __routebox_is_good (e->rb)); 00494 assert ((e->rb->flags.homeless ? e->rb->refcount > 0 : 1)); 00495 assert ((0 <= e->expand_dir) && (e->expand_dir < 9) 00496 && (e->flags. 00497 is_interior ? (e->expand_dir == ALL 00498 && e->rb->conflicts_with) : 1)); 00499 assert ((e->flags.is_via ? e->rb->flags.is_via : 1) 00500 && (e->flags.via_conflict_level >= 0 00501 && e->flags.via_conflict_level <= 2) 00502 && (e->flags.via_conflict_level != 0 ? e->flags.is_via : 1)); 00503 assert ((e->cost_to_point >= 0) && e->cost >= 0); 00504 return 1; 00505 } 00506 00507 int 00508 no_planes (const BoxType * b, void *cl) 00509 { 00510 routebox_t *rb = (routebox_t *) b; 00511 if (rb->type == PLANE) 00512 return 0; 00513 return 1; 00514 } 00515 #endif /* !NDEBUG */ 00516 00517 /*--------------------------------------------------------------------- 00518 * route utility functions. 00519 */ 00520 00521 enum boxlist 00522 { NET, SUBNET, ORIGINAL, DIFFERENT_NET }; 00523 static struct routebox_list * 00524 __select_list (routebox_t * r, enum boxlist which) 00525 { 00526 assert (r); 00527 switch (which) 00528 { 00529 default: 00530 assert (0); 00531 case NET: 00532 return &(r->same_net); 00533 case SUBNET: 00534 return &(r->same_subnet); 00535 case ORIGINAL: 00536 return &(r->original_subnet); 00537 case DIFFERENT_NET: 00538 return &(r->different_net); 00539 } 00540 } 00541 static void 00542 InitLists (routebox_t * r) 00543 { 00544 static enum boxlist all[] = 00545 { NET, SUBNET, ORIGINAL, DIFFERENT_NET } 00546 , *p; 00547 for (p = all; p < all + (sizeof (all) / sizeof (*p)); p++) 00548 { 00549 struct routebox_list *rl = __select_list (r, *p); 00550 rl->prev = rl->next = r; 00551 } 00552 } 00553 00554 static void 00555 MergeNets (routebox_t * a, routebox_t * b, enum boxlist which) 00556 { 00557 struct routebox_list *al, *bl, *anl, *bnl; 00558 routebox_t *an, *bn; 00559 assert (a && b); 00560 assert (a != b); 00561 assert (a->type != EXPANSION_AREA); 00562 assert (b->type != EXPANSION_AREA); 00563 al = __select_list (a, which); 00564 bl = __select_list (b, which); 00565 assert (al && bl); 00566 an = al->next; 00567 bn = bl->next; 00568 assert (an && bn); 00569 anl = __select_list (an, which); 00570 bnl = __select_list (bn, which); 00571 assert (anl && bnl); 00572 bl->next = an; 00573 anl->prev = b; 00574 al->next = bn; 00575 bnl->prev = a; 00576 } 00577 00578 static void 00579 RemoveFromNet (routebox_t * a, enum boxlist which) 00580 { 00581 struct routebox_list *al, *anl, *apl; 00582 routebox_t *an, *ap; 00583 assert (a); 00584 al = __select_list (a, which); 00585 assert (al); 00586 an = al->next; 00587 ap = al->prev; 00588 if (an == a || ap == a) 00589 return; /* not on any list */ 00590 assert (an && ap); 00591 anl = __select_list (an, which); 00592 apl = __select_list (ap, which); 00593 assert (anl && apl); 00594 anl->prev = ap; 00595 apl->next = an; 00596 al->next = al->prev = a; 00597 return; 00598 } 00599 00600 static void 00601 init_const_box (routebox_t * rb, 00602 Coord X1, Coord Y1, Coord X2, 00603 Coord Y2, Coord keepaway) 00604 { 00605 BoxType *bp = (BoxType *) & rb->box; /* note discarding const! */ 00606 assert (!rb->flags.inited); 00607 assert (X1 <= X2 && Y1 <= Y2); 00608 bp->X1 = X1 - keepaway; 00609 bp->Y1 = Y1 - keepaway; 00610 bp->X2 = X2 + keepaway; 00611 bp->Y2 = Y2 + keepaway; 00612 bp = (BoxType *) & rb->sbox; 00613 bp->X1 = X1; 00614 bp->Y1 = Y1; 00615 bp->X2 = X2; 00616 bp->Y2 = Y2; 00617 rb->flags.inited = 1; 00618 } 00619 00620 static inline BoxType 00621 shrink_routebox (const routebox_t * rb) 00622 { 00623 return rb->sbox; 00624 } 00625 00626 static inline cost_t 00627 box_area (const BoxType b) 00628 { 00629 cost_t ans = b.X2 - b.X1; 00630 return ans * (b.Y2 - b.Y1); 00631 } 00632 00633 static inline CheapPointType 00634 closest_point_in_routebox (const CheapPointType * from, const routebox_t * rb) 00635 { 00636 return closest_point_in_box (from, &rb->sbox); 00637 } 00638 00639 static inline bool 00640 point_in_shrunk_box (const routebox_t * box, Coord X, Coord Y) 00641 { 00642 BoxType b = shrink_routebox (box); 00643 return point_in_box (&b, X, Y); 00644 } 00645 00646 /*--------------------------------------------------------------------- 00647 * routedata initialization functions. 00648 */ 00649 00650 static routebox_t * 00651 AddPin (PointerListType layergroupboxes[], PinType *pin, bool is_via, 00652 RouteStyleType * style) 00653 { 00654 routebox_t **rbpp, *lastrb = NULL; 00655 int i, ht; 00656 /* a pin cuts through every layer group */ 00657 for (i = 0; i < max_group; i++) 00658 { 00659 rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[i]); 00660 *rbpp = (routebox_t *)malloc (sizeof (**rbpp)); 00661 memset ((void *) *rbpp, 0, sizeof (**rbpp)); 00662 (*rbpp)->group = i; 00663 ht = HALF_THICK (MAX (pin->Thickness, pin->DrillingHole)); 00664 init_const_box (*rbpp, 00665 /*X1 */ pin->X - ht, 00666 /*Y1 */ pin->Y - ht, 00667 /*X2 */ pin->X + ht, 00668 /*Y2 */ pin->Y + ht, style->Keepaway); 00669 /* set aux. properties */ 00670 if (is_via) 00671 { 00672 (*rbpp)->type = VIA; 00673 (*rbpp)->parent.via = pin; 00674 } 00675 else 00676 { 00677 (*rbpp)->type = PIN; 00678 (*rbpp)->parent.pin = pin; 00679 } 00680 (*rbpp)->flags.fixed = 1; 00681 (*rbpp)->came_from = ALL; 00682 (*rbpp)->style = style; 00683 (*rbpp)->flags.circular = !TEST_FLAG (SQUAREFLAG, pin); 00684 /* circular lists */ 00685 InitLists (*rbpp); 00686 /* link together */ 00687 if (lastrb) 00688 { 00689 MergeNets (*rbpp, lastrb, NET); 00690 MergeNets (*rbpp, lastrb, SUBNET); 00691 MergeNets (*rbpp, lastrb, ORIGINAL); 00692 } 00693 lastrb = *rbpp; 00694 } 00695 return lastrb; 00696 } 00697 static routebox_t * 00698 AddPad (PointerListType layergroupboxes[], 00699 ElementType *element, PadType *pad, RouteStyleType * style) 00700 { 00701 Coord halfthick; 00702 routebox_t **rbpp; 00703 int layergroup = (TEST_FLAG (ONSOLDERFLAG, pad) ? back : front); 00704 assert (0 <= layergroup && layergroup < max_group); 00705 assert (PCB->LayerGroups.Number[layergroup] > 0); 00706 rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[layergroup]); 00707 assert (rbpp); 00708 *rbpp = (routebox_t *)malloc (sizeof (**rbpp)); 00709 assert (*rbpp); 00710 memset (*rbpp, 0, sizeof (**rbpp)); 00711 (*rbpp)->group = layergroup; 00712 halfthick = HALF_THICK (pad->Thickness); 00713 init_const_box (*rbpp, 00714 /*X1 */ MIN (pad->Point1.X, pad->Point2.X) - halfthick, 00715 /*Y1 */ MIN (pad->Point1.Y, pad->Point2.Y) - halfthick, 00716 /*X2 */ MAX (pad->Point1.X, pad->Point2.X) + halfthick, 00717 /*Y2 */ MAX (pad->Point1.Y, pad->Point2.Y) + halfthick, 00718 style->Keepaway); 00719 /* kludge for non-manhattan pads (which are not allowed at present) */ 00720 if (pad->Point1.X != pad->Point2.X && pad->Point1.Y != pad->Point2.Y) 00721 (*rbpp)->flags.nonstraight = 1; 00722 /* set aux. properties */ 00723 (*rbpp)->type = PAD; 00724 (*rbpp)->parent.pad = pad; 00725 (*rbpp)->flags.fixed = 1; 00726 (*rbpp)->came_from = ALL; 00727 (*rbpp)->style = style; 00728 /* circular lists */ 00729 InitLists (*rbpp); 00730 return *rbpp; 00731 } 00732 static routebox_t * 00733 AddLine (PointerListType layergroupboxes[], int layergroup, LineType *line, 00734 LineType *ptr, RouteStyleType * style) 00735 { 00736 routebox_t **rbpp; 00737 assert (layergroupboxes && line); 00738 assert (0 <= layergroup && layergroup < max_group); 00739 assert (PCB->LayerGroups.Number[layergroup] > 0); 00740 00741 rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[layergroup]); 00742 *rbpp = (routebox_t *)malloc (sizeof (**rbpp)); 00743 memset (*rbpp, 0, sizeof (**rbpp)); 00744 (*rbpp)->group = layergroup; 00745 init_const_box (*rbpp, 00746 /*X1 */ MIN (line->Point1.X, 00747 line->Point2.X) - HALF_THICK (line->Thickness), 00748 /*Y1 */ MIN (line->Point1.Y, 00749 line->Point2.Y) - HALF_THICK (line->Thickness), 00750 /*X2 */ MAX (line->Point1.X, 00751 line->Point2.X) + HALF_THICK (line->Thickness), 00752 /*Y2 */ MAX (line->Point1.Y, 00753 line->Point2.Y) + 00754 HALF_THICK (line->Thickness), style->Keepaway); 00755 /* kludge for non-manhattan lines */ 00756 if (line->Point1.X != line->Point2.X && line->Point1.Y != line->Point2.Y) 00757 { 00758 (*rbpp)->flags.nonstraight = 1; 00759 (*rbpp)->flags.bl_to_ur = 00760 (MIN (line->Point1.X, line->Point2.X) == line->Point1.X) != 00761 (MIN (line->Point1.Y, line->Point2.Y) == line->Point1.Y); 00762 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ZIGZAG) 00763 showroutebox (*rbpp); 00764 #endif 00765 } 00766 /* set aux. properties */ 00767 (*rbpp)->type = LINE; 00768 (*rbpp)->parent.line = ptr; 00769 (*rbpp)->flags.fixed = 1; 00770 (*rbpp)->came_from = ALL; 00771 (*rbpp)->style = style; 00772 /* circular lists */ 00773 InitLists (*rbpp); 00774 return *rbpp; 00775 } 00776 static routebox_t * 00777 AddIrregularObstacle (PointerListType layergroupboxes[], 00778 Coord X1, Coord Y1, 00779 Coord X2, Coord Y2, Cardinal layergroup, 00780 void *parent, RouteStyleType * style) 00781 { 00782 routebox_t **rbpp; 00783 Coord keep = style->Keepaway; 00784 assert (layergroupboxes && parent); 00785 assert (X1 <= X2 && Y1 <= Y2); 00786 assert (0 <= layergroup && layergroup < max_group); 00787 assert (PCB->LayerGroups.Number[layergroup] > 0); 00788 00789 rbpp = (routebox_t **) GetPointerMemory (&layergroupboxes[layergroup]); 00790 *rbpp = (routebox_t *)malloc (sizeof (**rbpp)); 00791 memset (*rbpp, 0, sizeof (**rbpp)); 00792 (*rbpp)->group = layergroup; 00793 init_const_box (*rbpp, X1, Y1, X2, Y2, keep); 00794 (*rbpp)->flags.nonstraight = 1; 00795 (*rbpp)->type = OTHER; 00796 (*rbpp)->parent.generic = parent; 00797 (*rbpp)->flags.fixed = 1; 00798 (*rbpp)->style = style; 00799 /* circular lists */ 00800 InitLists (*rbpp); 00801 return *rbpp; 00802 } 00803 00804 static routebox_t * 00805 AddPolygon (PointerListType layergroupboxes[], Cardinal layer, 00806 PolygonType *polygon, RouteStyleType * style) 00807 { 00808 int is_not_rectangle = 1; 00809 int layergroup = GetLayerGroupNumberByNumber (layer); 00810 routebox_t *rb; 00811 assert (0 <= layergroup && layergroup < max_group); 00812 rb = AddIrregularObstacle (layergroupboxes, 00813 polygon->BoundingBox.X1, 00814 polygon->BoundingBox.Y1, 00815 polygon->BoundingBox.X2, 00816 polygon->BoundingBox.Y2, 00817 layergroup, polygon, style); 00818 if (polygon->PointN == 4 && 00819 polygon->HoleIndexN == 0 && 00820 (polygon->Points[0].X == polygon->Points[1].X || 00821 polygon->Points[0].Y == polygon->Points[1].Y) && 00822 (polygon->Points[1].X == polygon->Points[2].X || 00823 polygon->Points[1].Y == polygon->Points[2].Y) && 00824 (polygon->Points[2].X == polygon->Points[3].X || 00825 polygon->Points[2].Y == polygon->Points[3].Y) && 00826 (polygon->Points[3].X == polygon->Points[0].X || 00827 polygon->Points[3].Y == polygon->Points[0].Y)) 00828 is_not_rectangle = 0; 00829 rb->flags.nonstraight = is_not_rectangle; 00830 rb->layer = layer; 00831 rb->came_from = ALL; 00832 if (TEST_FLAG (CLEARPOLYFLAG, polygon)) 00833 { 00834 rb->flags.clear_poly = 1; 00835 if (!is_not_rectangle) 00836 rb->type = PLANE; 00837 } 00838 return rb; 00839 } 00840 static void 00841 AddText (PointerListType layergroupboxes[], Cardinal layergroup, 00842 TextType *text, RouteStyleType * style) 00843 { 00844 AddIrregularObstacle (layergroupboxes, 00845 text->BoundingBox.X1, text->BoundingBox.Y1, 00846 text->BoundingBox.X2, text->BoundingBox.Y2, 00847 layergroup, text, style); 00848 } 00849 static routebox_t * 00850 AddArc (PointerListType layergroupboxes[], Cardinal layergroup, 00851 ArcType *arc, RouteStyleType * style) 00852 { 00853 return AddIrregularObstacle (layergroupboxes, 00854 arc->BoundingBox.X1, arc->BoundingBox.Y1, 00855 arc->BoundingBox.X2, arc->BoundingBox.Y2, 00856 layergroup, arc, style); 00857 } 00858 00859 struct rb_info 00860 { 00861 BoxType query; 00862 routebox_t *winner; 00863 jmp_buf env; 00864 }; 00865 00866 static int 00867 __found_one_on_lg (const BoxType * box, void *cl) 00868 { 00869 struct rb_info *inf = (struct rb_info *) cl; 00870 routebox_t *rb = (routebox_t *) box; 00871 BoxType sb; 00872 00873 if (rb->flags.nonstraight) 00874 return 0; 00875 sb = shrink_box (&rb->box, rb->style->Keepaway); 00876 if (inf->query.X1 >= sb.X2 || inf->query.X2 <= sb.X1 || 00877 inf->query.Y1 >= sb.Y2 || inf->query.Y2 <= sb.Y1) 00878 return 0; 00879 inf->winner = rb; 00880 if (rb->type == PLANE) 00881 return 1; /* keep looking for something smaller if a plane was found */ 00882 longjmp (inf->env, 1); 00883 return 0; 00884 } 00885 static routebox_t * 00886 FindRouteBoxOnLayerGroup (routedata_t * rd, 00887 Coord X, Coord Y, Cardinal layergroup) 00888 { 00889 struct rb_info info; 00890 info.winner = NULL; 00891 info.query = point_box (X, Y); 00892 if (setjmp (info.env) == 0) 00893 r_search (rd->layergrouptree[layergroup], &info.query, NULL, 00894 __found_one_on_lg, &info); 00895 return info.winner; 00896 } 00897 00898 #ifdef ROUTE_DEBUG_VERBOSE 00899 static void 00900 DumpRouteBox (routebox_t * rb) 00901 { 00902 pcb_printf ("RB: %#mD-%#mD l%d; ", 00903 rb->box.X1, rb->box.Y1, rb->box.X2, rb->box.Y2, (int) rb->group); 00904 switch (rb->type) 00905 { 00906 case PAD: 00907 printf ("PAD[%s %s] ", rb->parent.pad->Name, rb->parent.pad->Number); 00908 break; 00909 case PIN: 00910 printf ("PIN[%s %s] ", rb->parent.pin->Name, rb->parent.pin->Number); 00911 break; 00912 case VIA: 00913 if (!rb->parent.via) 00914 break; 00915 printf ("VIA[%s %s] ", rb->parent.via->Name, rb->parent.via->Number); 00916 break; 00917 case LINE: 00918 printf ("LINE "); 00919 break; 00920 case OTHER: 00921 printf ("OTHER "); 00922 break; 00923 case EXPANSION_AREA: 00924 printf ("EXPAREA "); 00925 break; 00926 default: 00927 printf ("UNKNOWN "); 00928 break; 00929 } 00930 if (rb->flags.nonstraight) 00931 printf ("(nonstraight) "); 00932 if (rb->flags.fixed) 00933 printf ("(fixed) "); 00934 if (rb->flags.source) 00935 printf ("(source) "); 00936 if (rb->flags.target) 00937 printf ("(target) "); 00938 if (rb->flags.homeless) 00939 printf ("(homeless) "); 00940 printf ("\n"); 00941 } 00942 #endif 00943 00944 static routedata_t * 00945 CreateRouteData () 00946 { 00947 NetListListType Nets; 00948 PointerListType layergroupboxes[MAX_GROUP]; 00949 BoxType bbox; 00950 routedata_t *rd; 00951 int group, i; 00952 00953 /* check which layers are active first */ 00954 routing_layers = 0; 00955 for (group = 0; group < max_group; group++) 00956 { 00957 for (i = 0; i < PCB->LayerGroups.Number[group]; i++) 00958 /* layer must be 1) not silk (ie, < max_copper_layer) and 2) on */ 00959 if ((PCB->LayerGroups.Entries[group][i] < max_copper_layer) && 00960 PCB->Data->Layer[PCB->LayerGroups.Entries[group][i]].On) 00961 { 00962 routing_layers++; 00963 is_layer_group_active[group] = true; 00964 break; 00965 } 00966 else 00967 is_layer_group_active[group] = false; 00968 } 00969 /* if via visibility is turned off, don't use them */ 00970 AutoRouteParameters.use_vias = routing_layers > 1 && PCB->ViaOn; 00971 front = GetLayerGroupNumberBySide (TOP_SIDE); 00972 back = GetLayerGroupNumberBySide (BOTTOM_SIDE); 00973 /* determine preferred routing direction on each group */ 00974 for (i = 0; i < max_group; i++) 00975 { 00976 if (i != back && i != front) 00977 { 00978 x_cost[i] = (i & 1) ? 2 : 1; 00979 y_cost[i] = (i & 1) ? 1 : 2; 00980 } 00981 else if (i == back) 00982 { 00983 x_cost[i] = 4; 00984 y_cost[i] = 2; 00985 } 00986 else 00987 { 00988 x_cost[i] = 2; 00989 y_cost[i] = 2; 00990 } 00991 } 00992 /* create routedata */ 00993 rd = (routedata_t *)malloc (sizeof (*rd)); 00994 memset ((void *) rd, 0, sizeof (*rd)); 00995 /* create default style */ 00996 rd->defaultstyle.Thick = Settings.LineThickness; 00997 rd->defaultstyle.Diameter = Settings.ViaThickness; 00998 rd->defaultstyle.Hole = Settings.ViaDrillingHole; 00999 rd->defaultstyle.Keepaway = Settings.Keepaway; 01000 rd->max_bloat = BLOAT (&rd->defaultstyle); 01001 rd->max_keep = Settings.Keepaway; 01002 /* create styles structures */ 01003 bbox.X1 = bbox.Y1 = 0; 01004 bbox.X2 = PCB->MaxWidth; 01005 bbox.Y2 = PCB->MaxHeight; 01006 for (i = 0; i < NUM_STYLES + 1; i++) 01007 { 01008 RouteStyleType *style = 01009 (i < NUM_STYLES) ? &PCB->RouteStyle[i] : &rd->defaultstyle; 01010 rd->styles[i] = style; 01011 } 01012 01013 /* initialize pointerlisttype */ 01014 for (i = 0; i < max_group; i++) 01015 { 01016 layergroupboxes[i].Ptr = NULL; 01017 layergroupboxes[i].PtrN = 0; 01018 layergroupboxes[i].PtrMax = 0; 01019 GROUP_LOOP (PCB->Data, i); 01020 { 01021 if (layer->LineN || layer->ArcN) 01022 usedGroup[i] = true; 01023 else 01024 usedGroup[i] = false; 01025 } 01026 END_LOOP; 01027 } 01028 usedGroup[front] = true; 01029 usedGroup[back] = true; 01030 /* add the objects in the netlist first. 01031 * then go and add all other objects that weren't already added 01032 * 01033 * this saves on searching the trees to find the nets 01034 */ 01035 /* use the DRCFLAG to mark objects as they are entered */ 01036 Nets = CollectSubnets (false); 01037 { 01038 routebox_t *last_net = NULL; 01039 NETLIST_LOOP (&Nets); 01040 { 01041 routebox_t *last_in_net = NULL; 01042 NET_LOOP (netlist); 01043 { 01044 routebox_t *last_in_subnet = NULL; 01045 int j; 01046 01047 for (j = 0; j < NUM_STYLES; j++) 01048 if (net->Style == rd->styles[j]) 01049 break; 01050 CONNECTION_LOOP (net); 01051 { 01052 routebox_t *rb = NULL; 01053 SET_FLAG (DRCFLAG, (PinType *) connection->ptr2); 01054 if (connection->type == LINE_TYPE) 01055 { 01056 LineType *line = (LineType *) connection->ptr2; 01057 01058 /* lines are listed at each end, so skip one */ 01059 /* this should probably by a macro named "BUMP_LOOP" */ 01060 n--; 01061 01062 /* dice up non-straight lines into many tiny obstacles */ 01063 if (line->Point1.X != line->Point2.X 01064 && line->Point1.Y != line->Point2.Y) 01065 { 01066 LineType fake_line = *line; 01067 Coord dx = (line->Point2.X - line->Point1.X); 01068 Coord dy = (line->Point2.Y - line->Point1.Y); 01069 int segs = MAX (ABS (dx), 01070 ABS (dy)) / (4 * BLOAT (rd->styles[j]) + 1); 01071 int qq; 01072 segs = CLAMP (segs, 1, 32); /* don't go too crazy */ 01073 dx /= segs; 01074 dy /= segs; 01075 for (qq = 0; qq < segs - 1; qq++) 01076 { 01077 fake_line.Point2.X = fake_line.Point1.X + dx; 01078 fake_line.Point2.Y = fake_line.Point1.Y + dy; 01079 if (fake_line.Point2.X == line->Point2.X 01080 && fake_line.Point2.Y == line->Point2.Y) 01081 break; 01082 rb = 01083 AddLine (layergroupboxes, connection->group, 01084 &fake_line, line, rd->styles[j]); 01085 if (last_in_subnet && rb != last_in_subnet) 01086 MergeNets (last_in_subnet, rb, ORIGINAL); 01087 if (last_in_net && rb != last_in_net) 01088 MergeNets (last_in_net, rb, NET); 01089 last_in_subnet = last_in_net = rb; 01090 fake_line.Point1 = fake_line.Point2; 01091 } 01092 fake_line.Point2 = line->Point2; 01093 rb = 01094 AddLine (layergroupboxes, connection->group, &fake_line, 01095 line, rd->styles[j]); 01096 } 01097 else 01098 { 01099 rb = 01100 AddLine (layergroupboxes, connection->group, line, line, 01101 rd->styles[j]); 01102 } 01103 } 01104 else 01105 switch (connection->type) 01106 { 01107 case PAD_TYPE: 01108 rb = 01109 AddPad (layergroupboxes, (ElementType *)connection->ptr1, 01110 (PadType *)connection->ptr2, rd->styles[j]); 01111 break; 01112 case PIN_TYPE: 01113 rb = 01114 AddPin (layergroupboxes, (PinType *)connection->ptr2, false, 01115 rd->styles[j]); 01116 break; 01117 case VIA_TYPE: 01118 rb = 01119 AddPin (layergroupboxes, (PinType *)connection->ptr2, true, 01120 rd->styles[j]); 01121 break; 01122 case POLYGON_TYPE: 01123 rb = 01124 AddPolygon (layergroupboxes, 01125 GetLayerNumber (PCB->Data, (LayerType *)connection->ptr1), 01126 (struct polygon_st *)connection->ptr2, rd->styles[j]); 01127 break; 01128 } 01129 assert (rb); 01130 /* update circular connectivity lists */ 01131 if (last_in_subnet && rb != last_in_subnet) 01132 MergeNets (last_in_subnet, rb, ORIGINAL); 01133 if (last_in_net && rb != last_in_net) 01134 MergeNets (last_in_net, rb, NET); 01135 last_in_subnet = last_in_net = rb; 01136 rd->max_bloat = MAX (rd->max_bloat, BLOAT (rb->style)); 01137 rd->max_keep = MAX (rd->max_keep, rb->style->Keepaway); 01138 } 01139 END_LOOP; 01140 } 01141 END_LOOP; 01142 if (last_net && last_in_net) 01143 MergeNets (last_net, last_in_net, DIFFERENT_NET); 01144 last_net = last_in_net; 01145 } 01146 END_LOOP; 01147 rd->first_net = last_net; 01148 } 01149 FreeNetListListMemory (&Nets); 01150 01151 /* reset all nets to "original" connectivity (which we just set) */ 01152 { 01153 routebox_t *net; 01154 LIST_LOOP (rd->first_net, different_net, net); 01155 ResetSubnet (net); 01156 END_LOOP; 01157 } 01158 01159 /* add pins and pads of elements */ 01160 ALLPIN_LOOP (PCB->Data); 01161 { 01162 if (TEST_FLAG (DRCFLAG, pin)) 01163 CLEAR_FLAG (DRCFLAG, pin); 01164 else 01165 AddPin (layergroupboxes, pin, false, rd->styles[NUM_STYLES]); 01166 } 01167 ENDALL_LOOP; 01168 ALLPAD_LOOP (PCB->Data); 01169 { 01170 if (TEST_FLAG (DRCFLAG, pad)) 01171 CLEAR_FLAG (DRCFLAG, pad); 01172 else 01173 AddPad (layergroupboxes, element, pad, rd->styles[NUM_STYLES]); 01174 } 01175 ENDALL_LOOP; 01176 /* add all vias */ 01177 VIA_LOOP (PCB->Data); 01178 { 01179 if (TEST_FLAG (DRCFLAG, via)) 01180 CLEAR_FLAG (DRCFLAG, via); 01181 else 01182 AddPin (layergroupboxes, via, true, rd->styles[NUM_STYLES]); 01183 } 01184 END_LOOP; 01185 01186 for (i = 0; i < max_copper_layer; i++) 01187 { 01188 int layergroup = GetLayerGroupNumberByNumber (i); 01189 /* add all (non-rat) lines */ 01190 LINE_LOOP (LAYER_PTR (i)); 01191 { 01192 if (TEST_FLAG (DRCFLAG, line)) 01193 { 01194 CLEAR_FLAG (DRCFLAG, line); 01195 continue; 01196 } 01197 /* dice up non-straight lines into many tiny obstacles */ 01198 if (line->Point1.X != line->Point2.X 01199 && line->Point1.Y != line->Point2.Y) 01200 { 01201 LineType fake_line = *line; 01202 Coord dx = (line->Point2.X - line->Point1.X); 01203 Coord dy = (line->Point2.Y - line->Point1.Y); 01204 int segs = MAX (ABS (dx), ABS (dy)) / (4 * rd->max_bloat + 1); 01205 int qq; 01206 segs = CLAMP (segs, 1, 32); /* don't go too crazy */ 01207 dx /= segs; 01208 dy /= segs; 01209 for (qq = 0; qq < segs - 1; qq++) 01210 { 01211 fake_line.Point2.X = fake_line.Point1.X + dx; 01212 fake_line.Point2.Y = fake_line.Point1.Y + dy; 01213 if (fake_line.Point2.X == line->Point2.X 01214 && fake_line.Point2.Y == line->Point2.Y) 01215 break; 01216 AddLine (layergroupboxes, layergroup, &fake_line, line, 01217 rd->styles[NUM_STYLES]); 01218 fake_line.Point1 = fake_line.Point2; 01219 } 01220 fake_line.Point2 = line->Point2; 01221 AddLine (layergroupboxes, layergroup, &fake_line, line, 01222 rd->styles[NUM_STYLES]); 01223 } 01224 else 01225 { 01226 AddLine (layergroupboxes, layergroup, line, line, 01227 rd->styles[NUM_STYLES]); 01228 } 01229 } 01230 END_LOOP; 01231 /* add all polygons */ 01232 POLYGON_LOOP (LAYER_PTR (i)); 01233 { 01234 if (TEST_FLAG (DRCFLAG, polygon)) 01235 CLEAR_FLAG (DRCFLAG, polygon); 01236 else 01237 AddPolygon (layergroupboxes, i, polygon, rd->styles[NUM_STYLES]); 01238 } 01239 END_LOOP; 01240 /* add all copper text */ 01241 TEXT_LOOP (LAYER_PTR (i)); 01242 { 01243 AddText (layergroupboxes, layergroup, text, rd->styles[NUM_STYLES]); 01244 } 01245 END_LOOP; 01246 /* add all arcs */ 01247 ARC_LOOP (LAYER_PTR (i)); 01248 { 01249 AddArc (layergroupboxes, layergroup, arc, rd->styles[NUM_STYLES]); 01250 } 01251 END_LOOP; 01252 } 01253 01254 /* create r-trees from pointer lists */ 01255 for (i = 0; i < max_group; i++) 01256 { 01257 /* create the r-tree */ 01258 rd->layergrouptree[i] = 01259 r_create_tree ((const BoxType **) layergroupboxes[i].Ptr, 01260 layergroupboxes[i].PtrN, 1); 01261 } 01262 01263 if (AutoRouteParameters.use_vias) 01264 { 01265 rd->mtspace = mtspace_create (); 01266 01267 /* create "empty-space" structures for via placement (now that we know 01268 * appropriate keepaways for all the fixed elements) */ 01269 for (i = 0; i < max_group; i++) 01270 { 01271 POINTER_LOOP (&layergroupboxes[i]); 01272 { 01273 routebox_t *rb = (routebox_t *) * ptr; 01274 if (!rb->flags.clear_poly) 01275 mtspace_add (rd->mtspace, &rb->box, FIXED, rb->style->Keepaway); 01276 } 01277 END_LOOP; 01278 } 01279 } 01280 /* free pointer lists */ 01281 for (i = 0; i < max_group; i++) 01282 FreePointerListMemory (&layergroupboxes[i]); 01283 /* done! */ 01284 return rd; 01285 } 01286 01287 void 01288 DestroyRouteData (routedata_t ** rd) 01289 { 01290 int i; 01291 for (i = 0; i < max_group; i++) 01292 r_destroy_tree (&(*rd)->layergrouptree[i]); 01293 if (AutoRouteParameters.use_vias) 01294 mtspace_destroy (&(*rd)->mtspace); 01295 free (*rd); 01296 *rd = NULL; 01297 } 01298 01299 /*----------------------------------------------------------------- 01300 * routebox reference counting. 01301 */ 01302 01306 static void 01307 RB_up_count (routebox_t * rb) 01308 { 01309 assert (rb->flags.homeless); 01310 rb->refcount++; 01311 } 01312 01317 static void 01318 RB_down_count (routebox_t * rb) 01319 { 01320 assert (rb->type == EXPANSION_AREA); 01321 assert (rb->flags.homeless); 01322 assert (rb->refcount > 0); 01323 if (--rb->refcount == 0) 01324 { 01325 if (rb->parent.expansion_area->flags.homeless) 01326 RB_down_count (rb->parent.expansion_area); 01327 free (rb); 01328 } 01329 } 01330 01331 /*----------------------------------------------------------------- 01332 * Rectangle-expansion routing code. 01333 */ 01334 01335 static void 01336 ResetSubnet (routebox_t * net) 01337 { 01338 routebox_t *rb; 01339 /* reset connectivity of everything on this net */ 01340 LIST_LOOP (net, same_net, rb); 01341 rb->same_subnet = rb->original_subnet; 01342 END_LOOP; 01343 } 01344 01345 static inline cost_t 01346 cost_to_point_on_layer (const CheapPointType * p1, 01347 const CheapPointType * p2, Cardinal point_layer) 01348 { 01349 cost_t x_dist = p1->X - p2->X, y_dist = p1->Y - p2->Y, r; 01350 x_dist *= x_cost[point_layer]; 01351 y_dist *= y_cost[point_layer]; 01352 /* cost is proportional to orthogonal distance. */ 01353 r = ABS (x_dist) + ABS (y_dist); 01354 if (p1->X != p2->X && p1->Y != p2->Y) 01355 r += AutoRouteParameters.JogPenalty; 01356 return r; 01357 } 01358 01359 static cost_t 01360 cost_to_point (const CheapPointType * p1, Cardinal point_layer1, 01361 const CheapPointType * p2, Cardinal point_layer2) 01362 { 01363 cost_t r = cost_to_point_on_layer (p1, p2, point_layer1); 01364 /* apply via cost penalty if layers differ */ 01365 if (point_layer1 != point_layer2) 01366 r += AutoRouteParameters.ViaCost; 01367 return r; 01368 } 01369 01375 static cost_t 01376 cost_to_layerless_box (const CheapPointType * p, Cardinal point_layer, 01377 const BoxType * b) 01378 { 01379 CheapPointType p2 = closest_point_in_box (p, b); 01380 register cost_t c1, c2; 01381 01382 c1 = p2.X - p->X; 01383 c2 = p2.Y - p->Y; 01384 01385 c1 = ABS (c1); 01386 c2 = ABS (c2); 01387 if (c1 < c2) 01388 return c1 * AutoRouteParameters.MinPenalty + c2; 01389 else 01390 return c2 * AutoRouteParameters.MinPenalty + c1; 01391 } 01392 01396 bool 01397 TargetPoint (CheapPointType * nextpoint, const routebox_t * target) 01398 { 01399 if (target->type == PIN) 01400 { 01401 nextpoint->X = target->parent.pin->X; 01402 nextpoint->Y = target->parent.pin->Y; 01403 return true; 01404 } 01405 else if (target->type == PAD) 01406 { 01407 if (abs (target->parent.pad->Point1.X - nextpoint->X) < 01408 abs (target->parent.pad->Point2.X - nextpoint->X)) 01409 nextpoint->X = target->parent.pad->Point1.X; 01410 else 01411 nextpoint->X = target->parent.pad->Point2.X; 01412 if (abs (target->parent.pad->Point1.Y - nextpoint->Y) < 01413 abs (target->parent.pad->Point2.Y - nextpoint->Y)) 01414 nextpoint->Y = target->parent.pad->Point1.Y; 01415 else 01416 nextpoint->Y = target->parent.pad->Point2.Y; 01417 return true; 01418 } 01419 else 01420 { 01421 nextpoint->X = CENTER_X (target->sbox); 01422 nextpoint->Y = CENTER_Y (target->sbox); 01423 } 01424 return false; 01425 } 01426 01434 static cost_t 01435 cost_to_routebox (const CheapPointType * p, Cardinal point_layer, 01436 const routebox_t * rb) 01437 { 01438 register cost_t trial = 0; 01439 CheapPointType p2 = closest_point_in_routebox (p, rb); 01440 if (!usedGroup[point_layer] || !usedGroup[rb->group]) 01441 trial = AutoRouteParameters.NewLayerPenalty; 01442 if ((p2.X - p->X) * (p2.Y - p->Y) != 0) 01443 trial += AutoRouteParameters.JogPenalty; 01444 /* special case for defered via searching */ 01445 if (point_layer > max_group || point_layer == rb->group) 01446 return trial + ABS (p2.X - p->X) + ABS (p2.Y - p->Y); 01447 /* if this target is only a via away, then the via is cheaper than the congestion */ 01448 if (p->X == p2.X && p->Y == p2.Y) 01449 return trial + 1; 01450 trial += AutoRouteParameters.ViaCost; 01451 trial += ABS (p2.X - p->X) + ABS (p2.Y - p->Y); 01452 return trial; 01453 } 01454 01455 01456 static BoxType 01457 bloat_routebox (routebox_t * rb) 01458 { 01459 BoxType r; 01460 Coord keepaway; 01461 assert (__routebox_is_good (rb)); 01462 01463 if (rb->flags.nobloat) 01464 return rb->sbox; 01465 01466 /* Obstacle exclusion zones get bloated by the larger of 01467 * the two required clearances plus half the track width. 01468 */ 01469 keepaway = MAX (AutoRouteParameters.style->Keepaway, rb->style->Keepaway); 01470 r = bloat_box (&rb->sbox, keepaway + 01471 HALF_THICK (AutoRouteParameters.style->Thick)); 01472 return r; 01473 } 01474 01475 01476 #ifdef ROUTE_DEBUG /* only for debugging expansion areas */ 01477 01481 void 01482 showbox (BoxType b, Dimension thickness, int group) 01483 { 01484 LineType *line; 01485 LayerType *SLayer = LAYER_PTR (group); 01486 if (showboxen < -1) 01487 return; 01488 if (showboxen != -1 && showboxen != group) 01489 return; 01490 01491 if (ddraw != NULL) 01492 { 01493 ddraw->set_line_width (ar_gc, thickness); 01494 ddraw->set_line_cap (ar_gc, Trace_Cap); 01495 ddraw->set_color (ar_gc, SLayer->Color); 01496 01497 ddraw->draw_line (ar_gc, b.X1, b.Y1, b.X2, b.Y1); 01498 ddraw->draw_line (ar_gc, b.X1, b.Y2, b.X2, b.Y2); 01499 ddraw->draw_line (ar_gc, b.X1, b.Y1, b.X1, b.Y2); 01500 ddraw->draw_line (ar_gc, b.X2, b.Y1, b.X2, b.Y2); 01501 } 01502 01503 #if 1 01504 if (b.Y1 == b.Y2 || b.X1 == b.X2) 01505 thickness = 5; 01506 line = CreateNewLineOnLayer (LAYER_PTR (top_silk_layer), 01507 b.X1, b.Y1, b.X2, b.Y1, thickness, 0, 01508 MakeFlags (0)); 01509 AddObjectToCreateUndoList (LINE_TYPE, 01510 LAYER_PTR (top_silk_layer), line, 01511 line); 01512 if (b.Y1 != b.Y2) 01513 { 01514 line = CreateNewLineOnLayer (LAYER_PTR (top_silk_layer), 01515 b.X1, b.Y2, b.X2, b.Y2, thickness, 0, 01516 MakeFlags (0)); 01517 AddObjectToCreateUndoList (LINE_TYPE, 01518 LAYER_PTR (bottom_silk_layer), 01519 line, line); 01520 } 01521 line = CreateNewLineOnLayer (LAYER_PTR (top_silk_layer), 01522 b.X1, b.Y1, b.X1, b.Y2, thickness, 0, 01523 MakeFlags (0)); 01524 AddObjectToCreateUndoList (LINE_TYPE, 01525 LAYER_PTR (top_silk_layer), line, 01526 line); 01527 if (b.X1 != b.X2) 01528 { 01529 line = CreateNewLineOnLayer (LAYER_PTR (top_silk_layer), 01530 b.X2, b.Y1, b.X2, b.Y2, thickness, 0, 01531 MakeFlags (0)); 01532 AddObjectToCreateUndoList (LINE_TYPE, 01533 LAYER_PTR (top_silk_layer), 01534 line, line); 01535 } 01536 #endif 01537 } 01538 #endif 01539 01540 #if defined(ROUTE_DEBUG) 01541 static void 01542 showedge (edge_t * e) 01543 { 01544 BoxType *b = (BoxType *) e->rb; 01545 01546 if (ddraw == NULL) 01547 return; 01548 01549 ddraw->set_line_cap (ar_gc, Trace_Cap); 01550 ddraw->set_line_width (ar_gc, 1); 01551 ddraw->set_color (ar_gc, Settings.MaskColor); 01552 01553 switch (e->expand_dir) 01554 { 01555 case NORTH: 01556 ddraw->draw_line (ar_gc, b->X1, b->Y1, b->X2, b->Y1); 01557 break; 01558 case SOUTH: 01559 ddraw->draw_line (ar_gc, b->X1, b->Y2, b->X2, b->Y2); 01560 break; 01561 case WEST: 01562 ddraw->draw_line (ar_gc, b->X1, b->Y1, b->X1, b->Y2); 01563 break; 01564 case EAST: 01565 ddraw->draw_line (ar_gc, b->X2, b->Y1, b->X2, b->Y2); 01566 break; 01567 default: 01568 break; 01569 } 01570 } 01571 #endif 01572 01573 #if defined(ROUTE_DEBUG) 01574 static void 01575 showroutebox (routebox_t * rb) 01576 { 01577 showbox (rb->sbox, rb->flags.source ? 20 : (rb->flags.target ? 10 : 1), 01578 rb->flags.is_via ? top_silk_layer : rb->group); 01579 } 01580 #endif 01581 01586 static routebox_t * 01587 route_parent (routebox_t * rb) 01588 { 01589 while (rb->flags.homeless && !rb->flags.is_via && !rb->flags.is_thermal) 01590 { 01591 assert (rb->type == EXPANSION_AREA); 01592 rb = rb->parent.expansion_area; 01593 assert (rb); 01594 } 01595 return rb; 01596 } 01597 01598 static vector_t * 01599 path_conflicts (routebox_t * rb, routebox_t * conflictor, bool branch) 01600 { 01601 if (branch) 01602 rb->conflicts_with = vector_duplicate (rb->conflicts_with); 01603 else if (!rb->conflicts_with) 01604 rb->conflicts_with = vector_create (); 01605 vector_append (rb->conflicts_with, conflictor); 01606 return rb->conflicts_with; 01607 } 01608 01621 static void 01622 touch_conflicts (vector_t * conflicts, int touch) 01623 { 01624 static vector_t *last = NULL; 01625 static int last_size = 0; 01626 int i, n; 01627 i = 0; 01628 if (touch) 01629 { 01630 if (last && conflicts != last) 01631 touch_conflicts (last, 0); 01632 if (!conflicts) 01633 return; 01634 last = conflicts; 01635 i = last_size; 01636 } 01637 n = vector_size (conflicts); 01638 for (; i < n; i++) 01639 { 01640 routebox_t *rb = (routebox_t *) vector_element (conflicts, i); 01641 routebox_t *p; 01642 LIST_LOOP (rb, same_net, p); 01643 if (!p->flags.fixed) 01644 p->flags.touched = touch; 01645 END_LOOP; 01646 } 01647 if (!touch) 01648 { 01649 last = NULL; 01650 last_size = 0; 01651 } 01652 else 01653 last_size = n; 01654 } 01655 01663 static routebox_t * 01664 nonhomeless_parent (routebox_t * rb) 01665 { 01666 return route_parent (rb); 01667 } 01668 01673 struct mincost_target_closure 01674 { 01675 const CheapPointType *CostPoint; 01676 Cardinal CostPointLayer; 01677 routebox_t *nearest; 01678 cost_t nearest_cost; 01679 }; 01680 static int 01681 __region_within_guess (const BoxType * region, void *cl) 01682 { 01683 struct mincost_target_closure *mtc = (struct mincost_target_closure *) cl; 01684 cost_t cost_to_region; 01685 if (mtc->nearest == NULL) 01686 return 1; 01687 cost_to_region = 01688 cost_to_layerless_box (mtc->CostPoint, mtc->CostPointLayer, region); 01689 assert (cost_to_region >= 0); 01690 /* if no guess yet, all regions are "close enough" */ 01691 /* note that cost is *strictly more* than minimum distance, so we'll 01692 * always search a region large enough. */ 01693 return (cost_to_region < mtc->nearest_cost); 01694 } 01695 static int 01696 __found_new_guess (const BoxType * box, void *cl) 01697 { 01698 struct mincost_target_closure *mtc = (struct mincost_target_closure *) cl; 01699 routebox_t *guess = (routebox_t *) box; 01700 cost_t cost_to_guess = 01701 cost_to_routebox (mtc->CostPoint, mtc->CostPointLayer, guess); 01702 assert (cost_to_guess >= 0); 01703 /* if this is cheaper than previous guess... */ 01704 if (cost_to_guess < mtc->nearest_cost) 01705 { 01706 mtc->nearest = guess; 01707 mtc->nearest_cost = cost_to_guess; /* this is our new guess! */ 01708 return 1; 01709 } 01710 else 01711 return 0; /* not less expensive than our last guess */ 01712 } 01713 01720 static routebox_t * 01721 mincost_target_to_point (const CheapPointType * CostPoint, 01722 Cardinal CostPointLayer, 01723 rtree_t * targets, routebox_t * target_guess) 01724 { 01725 struct mincost_target_closure mtc; 01726 assert (target_guess == NULL || target_guess->flags.target); /* this is a target, right? */ 01727 mtc.CostPoint = CostPoint; 01728 mtc.CostPointLayer = CostPointLayer; 01729 mtc.nearest = target_guess; 01730 if (mtc.nearest) 01731 mtc.nearest_cost = 01732 cost_to_routebox (mtc.CostPoint, mtc.CostPointLayer, mtc.nearest); 01733 else 01734 mtc.nearest_cost = EXPENSIVE; 01735 r_search (targets, NULL, __region_within_guess, __found_new_guess, &mtc); 01736 assert (mtc.nearest != NULL && mtc.nearest_cost >= 0); 01737 assert (mtc.nearest->flags.target); /* this is a target, right? */ 01738 return mtc.nearest; 01739 } 01740 01746 static edge_t * 01747 CreateEdge (routebox_t * rb, 01748 Coord CostPointX, Coord CostPointY, 01749 cost_t cost_to_point, 01750 routebox_t * mincost_target_guess, 01751 direction_t expand_dir, rtree_t * targets) 01752 { 01753 edge_t *e; 01754 assert (__routebox_is_good (rb)); 01755 e = (edge_t *)malloc (sizeof (*e)); 01756 memset ((void *) e, 0, sizeof (*e)); 01757 assert (e); 01758 e->rb = rb; 01759 if (rb->flags.homeless) 01760 RB_up_count (rb); 01761 e->cost_point.X = CostPointX; 01762 e->cost_point.Y = CostPointY; 01763 e->cost_to_point = cost_to_point; 01764 e->flags.via_search = 0; 01765 /* if this edge is created in response to a target, use it */ 01766 if (targets) 01767 e->mincost_target = 01768 mincost_target_to_point (&e->cost_point, rb->group, 01769 targets, mincost_target_guess); 01770 else 01771 e->mincost_target = mincost_target_guess; 01772 e->expand_dir = expand_dir; 01773 assert (e->rb && e->mincost_target); /* valid edge? */ 01774 assert (!e->flags.is_via || e->expand_dir == ALL); 01775 /* cost point should be on edge (unless this is a plane/via/conflict edge) */ 01776 #if 0 01777 assert (rb->type == PLANE || rb->conflicts_with != NULL || rb->flags.is_via 01778 || rb->flags.is_thermal 01779 || ((expand_dir == NORTH || expand_dir == SOUTH) ? rb->sbox.X1 <= 01780 CostPointX && CostPointX < rb->sbox.X2 01781 && CostPointY == (expand_dir == 01782 NORTH ? rb->sbox.Y1 : rb->sbox.Y2 - 1) : 01783 /* expand_dir==EAST || expand_dir==WEST */ 01784 rb->sbox.Y1 <= CostPointY && CostPointY < rb->sbox.Y2 && 01785 CostPointX == (expand_dir == 01786 EAST ? rb->sbox.X2 - 1 : rb->sbox.X1))); 01787 #endif 01788 assert (__edge_is_good (e)); 01789 /* done */ 01790 return e; 01791 } 01792 01798 static edge_t * 01799 CreateEdge2 (routebox_t * rb, direction_t expand_dir, 01800 edge_t * previous_edge, rtree_t * targets, routebox_t * guess) 01801 { 01802 BoxType thisbox; 01803 CheapPointType thiscost, prevcost; 01804 cost_t d; 01805 01806 assert (rb && previous_edge); 01807 /* okay, find cheapest costpoint to costpoint of previous edge */ 01808 thisbox = edge_to_box (rb, expand_dir); 01809 prevcost = previous_edge->cost_point; 01810 /* find point closest to target */ 01811 thiscost = closest_point_in_box (&prevcost, &thisbox); 01812 /* compute cost-to-point */ 01813 d = cost_to_point_on_layer (&prevcost, &thiscost, rb->group); 01814 /* add in jog penalty */ 01815 if (previous_edge->expand_dir != expand_dir) 01816 d += AutoRouteParameters.JogPenalty; 01817 /* okay, new edge! */ 01818 return CreateEdge (rb, thiscost.X, thiscost.Y, 01819 previous_edge->cost_to_point + d, 01820 guess ? guess : previous_edge->mincost_target, 01821 expand_dir, targets); 01822 } 01823 01827 static edge_t * 01828 CreateViaEdge (const BoxType * area, Cardinal group, 01829 routebox_t * parent, edge_t * previous_edge, 01830 conflict_t to_site_conflict, 01831 conflict_t through_site_conflict, rtree_t * targets) 01832 { 01833 routebox_t *rb; 01834 CheapPointType costpoint; 01835 cost_t d; 01836 edge_t *ne; 01837 cost_t scale[3]; 01838 01839 scale[0] = 1; 01840 scale[1] = AutoRouteParameters.LastConflictPenalty; 01841 scale[2] = AutoRouteParameters.ConflictPenalty; 01842 01843 assert (box_is_good (area)); 01844 assert (AutoRouteParameters.with_conflicts || 01845 (to_site_conflict == NO_CONFLICT && 01846 through_site_conflict == NO_CONFLICT)); 01847 rb = CreateExpansionArea (area, group, parent, true, previous_edge); 01848 rb->flags.is_via = 1; 01849 rb->came_from = ALL; 01850 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_VIA_BOXES) 01851 showroutebox (rb); 01852 #endif /* ROUTE_DEBUG && DEBUG_SHOW_VIA_BOXES */ 01853 /* for planes, choose a point near the target */ 01854 if (previous_edge->flags.in_plane) 01855 { 01856 routebox_t *target; 01857 CheapPointType pnt; 01858 /* find a target near this via box */ 01859 pnt.X = CENTER_X (*area); 01860 pnt.Y = CENTER_Y (*area); 01861 target = mincost_target_to_point (&pnt, rb->group, 01862 targets, 01863 previous_edge->mincost_target); 01864 /* now find point near the target */ 01865 pnt.X = CENTER_X (target->box); 01866 pnt.Y = CENTER_Y (target->box); 01867 costpoint = closest_point_in_routebox (&pnt, rb); 01868 /* we moved from the previous cost point through the plane which is free travel */ 01869 d = 01870 (scale[through_site_conflict] * 01871 cost_to_point (&costpoint, group, &costpoint, 01872 previous_edge->rb->group)); 01873 ne = 01874 CreateEdge (rb, costpoint.X, costpoint.Y, 01875 previous_edge->cost_to_point + d, target, ALL, NULL); 01876 ne->mincost_target = target; 01877 } 01878 else 01879 { 01880 routebox_t *target; 01881 target = previous_edge->mincost_target; 01882 costpoint = closest_point_in_routebox (&previous_edge->cost_point, rb); 01883 d = 01884 (scale[to_site_conflict] * 01885 cost_to_point_on_layer (&costpoint, &previous_edge->cost_point, 01886 previous_edge->rb->group)) + 01887 (scale[through_site_conflict] * 01888 cost_to_point (&costpoint, group, &costpoint, 01889 previous_edge->rb->group)); 01890 /* if the target is just this via away, then this via is cheaper */ 01891 if (target->group == group && 01892 point_in_shrunk_box (target, costpoint.X, costpoint.Y)) 01893 d -= AutoRouteParameters.ViaCost / 2; 01894 ne = 01895 CreateEdge (rb, costpoint.X, costpoint.Y, 01896 previous_edge->cost_to_point + d, 01897 previous_edge->mincost_target, ALL, targets); 01898 } 01899 ne->flags.is_via = 1; 01900 ne->flags.via_conflict_level = to_site_conflict; 01901 assert (__edge_is_good (ne)); 01902 return ne; 01903 } 01904 01913 static edge_t * 01914 CreateEdgeWithConflicts (const BoxType * interior_edge, 01915 routebox_t * container, edge_t * previous_edge, 01916 cost_t cost_penalty_to_box, rtree_t * targets) 01917 { 01918 routebox_t *rb; 01919 CheapPointType costpoint; 01920 cost_t d; 01921 edge_t *ne; 01922 assert (interior_edge && container && previous_edge && targets); 01923 assert (!container->flags.homeless); 01924 assert (AutoRouteParameters.with_conflicts); 01925 assert (container->flags.touched == 0); 01926 assert (previous_edge->rb->group == container->group); 01927 /* use the caller's idea of what this box should be */ 01928 rb = 01929 CreateExpansionArea (interior_edge, previous_edge->rb->group, 01930 previous_edge->rb, true, previous_edge); 01931 path_conflicts (rb, container, true); /* crucial! */ 01932 costpoint = 01933 closest_point_in_box (&previous_edge->cost_point, interior_edge); 01934 d = 01935 cost_to_point_on_layer (&costpoint, &previous_edge->cost_point, 01936 previous_edge->rb->group); 01937 d *= cost_penalty_to_box; 01938 d += previous_edge->cost_to_point; 01939 ne = CreateEdge (rb, costpoint.X, costpoint.Y, d, NULL, ALL, targets); 01940 ne->flags.is_interior = 1; 01941 assert (__edge_is_good (ne)); 01942 return ne; 01943 } 01944 01945 static void 01946 KillEdge (void *edge) 01947 { 01948 edge_t *e = (edge_t *) edge; 01949 assert (e); 01950 if (e->rb->flags.homeless) 01951 RB_down_count (e->rb); 01952 if (e->flags.via_search) 01953 mtsFreeWork (&e->work); 01954 free (e); 01955 } 01956 01957 static void 01958 DestroyEdge (edge_t ** e) 01959 { 01960 assert (e && *e); 01961 KillEdge (*e); 01962 *e = NULL; 01963 } 01964 01968 static cost_t 01969 edge_cost (const edge_t * e, const cost_t too_big) 01970 { 01971 cost_t penalty = e->cost_to_point; 01972 if (e->rb->flags.is_thermal || e->rb->type == PLANE) 01973 return penalty; /* thermals are cheap */ 01974 if (penalty > too_big) 01975 return penalty; 01976 01977 /* cost_to_routebox adds in our via correction, too. */ 01978 return penalty + 01979 cost_to_routebox (&e->cost_point, e->rb->group, e->mincost_target); 01980 } 01981 01990 static BoxType 01991 edge_to_box (const routebox_t * rb, direction_t expand_dir) 01992 { 01993 BoxType b = shrink_routebox (rb); 01994 /* narrow box down to just the appropriate edge */ 01995 switch (expand_dir) 01996 { 01997 case NORTH: 01998 b.Y2 = b.Y1 + 1; 01999 break; 02000 case EAST: 02001 b.X1 = b.X2 - 1; 02002 break; 02003 case SOUTH: 02004 b.Y1 = b.Y2 - 1; 02005 break; 02006 case WEST: 02007 b.X2 = b.X1 + 1; 02008 break; 02009 default: 02010 assert (0); 02011 } 02012 /* done! */ 02013 return b; 02014 } 02015 02016 struct broken_boxes 02017 { 02018 BoxType left, center, right; 02019 bool is_valid_left, is_valid_center, is_valid_right; 02020 }; 02021 02022 static struct broken_boxes 02023 break_box_edge (const BoxType * original, direction_t which_edge, 02024 routebox_t * breaker) 02025 { 02026 BoxType origbox, breakbox; 02027 struct broken_boxes result; 02028 02029 assert (original && breaker); 02030 02031 origbox = *original; 02032 breakbox = bloat_routebox (breaker); 02033 ROTATEBOX_TO_NORTH (origbox, which_edge); 02034 ROTATEBOX_TO_NORTH (breakbox, which_edge); 02035 result.right.Y1 = result.center.Y1 = result.left.Y1 = origbox.Y1; 02036 result.right.Y2 = result.center.Y2 = result.left.Y2 = origbox.Y1 + 1; 02037 /* validity of breaker is not important because the boxes are marked invalid */ 02038 //assert (breakbox.X1 <= origbox.X2 && breakbox.X2 >= origbox.X1); 02039 /* left edge piece */ 02040 result.left.X1 = origbox.X1; 02041 result.left.X2 = breakbox.X1; 02042 /* center (ie blocked) edge piece */ 02043 result.center.X1 = MAX (breakbox.X1, origbox.X1); 02044 result.center.X2 = MIN (breakbox.X2, origbox.X2); 02045 /* right edge piece */ 02046 result.right.X1 = breakbox.X2; 02047 result.right.X2 = origbox.X2; 02048 /* validity: */ 02049 result.is_valid_left = (result.left.X1 < result.left.X2); 02050 result.is_valid_center = (result.center.X1 < result.center.X2); 02051 result.is_valid_right = (result.right.X1 < result.right.X2); 02052 /* rotate back */ 02053 ROTATEBOX_FROM_NORTH (result.left, which_edge); 02054 ROTATEBOX_FROM_NORTH (result.center, which_edge); 02055 ROTATEBOX_FROM_NORTH (result.right, which_edge); 02056 /* done */ 02057 return result; 02058 } 02059 02060 #ifndef NDEBUG 02061 static int 02062 share_edge (const BoxType * child, const BoxType * parent) 02063 { 02064 return 02065 (child->X1 == parent->X2 || child->X2 == parent->X1 || 02066 child->Y1 == parent->Y2 || child->Y2 == parent->Y1) && 02067 ((parent->X1 <= child->X1 && child->X2 <= parent->X2) || 02068 (parent->Y1 <= child->Y1 && child->Y2 <= parent->Y2)); 02069 } 02070 static int 02071 edge_intersect (const BoxType * child, const BoxType * parent) 02072 { 02073 return 02074 (child->X1 <= parent->X2) && (child->X2 >= parent->X1) && 02075 (child->Y1 <= parent->Y2) && (child->Y2 >= parent->Y1); 02076 } 02077 #endif 02078 02086 static routebox_t * 02087 CreateExpansionArea (const BoxType * area, Cardinal group, 02088 routebox_t * parent, 02089 bool relax_edge_requirements, edge_t * src_edge) 02090 { 02091 routebox_t *rb = (routebox_t *) malloc (sizeof (*rb)); 02092 memset ((void *) rb, 0, sizeof (*rb)); 02093 assert (area && parent); 02094 init_const_box (rb, area->X1, area->Y1, area->X2, area->Y2, 0); 02095 rb->group = group; 02096 rb->type = EXPANSION_AREA; 02097 /* should always share edge or overlap with parent */ 02098 assert (relax_edge_requirements ? box_intersect (&rb->sbox, &parent->sbox) 02099 : share_edge (&rb->sbox, &parent->sbox)); 02100 rb->parent.expansion_area = route_parent (parent); 02101 rb->cost_point = 02102 closest_point_in_box (&rb->parent.expansion_area->cost_point, area); 02103 rb->cost = 02104 rb->parent.expansion_area->cost + 02105 cost_to_point_on_layer (&rb->parent.expansion_area->cost_point, 02106 &rb->cost_point, rb->group); 02107 assert (relax_edge_requirements ? edge_intersect (&rb->sbox, &parent->sbox) 02108 : share_edge (&rb->sbox, &parent->sbox)); 02109 if (rb->parent.expansion_area->flags.homeless) 02110 RB_up_count (rb->parent.expansion_area); 02111 rb->flags.homeless = 1; 02112 rb->flags.nobloat = 1; 02113 rb->style = AutoRouteParameters.style; 02114 rb->conflicts_with = parent->conflicts_with; 02115 /* we will never link an EXPANSION_AREA into the nets because they 02116 * are *ONLY* used for path searching. No need to call InitLists () 02117 */ 02118 rb->came_from = src_edge->expand_dir; 02119 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EXPANSION_BOXES) 02120 showroutebox (rb); 02121 #endif /* ROUTE_DEBUG && DEBUG_SHOW_EXPANSION_BOXES */ 02122 return rb; 02123 } 02124 02125 /*------ Expand ------*/ 02126 struct E_result 02127 { 02128 routebox_t *parent; 02129 routebox_t *n, *e, *s, *w; 02130 Coord keep, bloat; 02131 BoxType inflated, orig; 02132 int done; 02133 }; 02134 02143 static int 02144 __Expand_this_rect (const BoxType * box, void *cl) 02145 { 02146 struct E_result *res = (struct E_result *) cl; 02147 routebox_t *rb = (routebox_t *) box; 02148 BoxType rbox; 02149 Coord dn, de, ds, dw, bloat; 02150 02151 /* we don't see conflicts already encountered */ 02152 if (rb->flags.touched) 02153 return 0; 02154 02155 /* The inflated box outer edges include its own 02156 * track width plus its own keepaway. 02157 * 02158 * To check for intersection, we need to expand 02159 * anything with greater keepaway by its excess 02160 * keepaway. 02161 * 02162 * If something has nobloat then we need to shrink 02163 * the inflated box back and see if it still touches. 02164 */ 02165 02166 if (rb->flags.nobloat) 02167 { 02168 rbox = rb->sbox; 02169 bloat = res->bloat; 02170 if (rbox.X2 <= res->inflated.X1 + bloat || 02171 rbox.X1 >= res->inflated.X2 - bloat || 02172 rbox.Y1 >= res->inflated.Y2 - bloat || 02173 rbox.Y2 <= res->inflated.Y1 + bloat) 02174 return 0; /* doesn't touch */ 02175 } 02176 else 02177 { 02178 if (rb->style->Keepaway > res->keep) 02179 rbox = bloat_box (&rb->sbox, rb->style->Keepaway - res->keep); 02180 else 02181 rbox = rb->sbox; 02182 02183 if (rbox.X2 <= res->inflated.X1 || rbox.X1 >= res->inflated.X2 02184 || rbox.Y1 >= res->inflated.Y2 || rbox.Y2 <= res->inflated.Y1) 02185 return 0; /* doesn't touch */ 02186 bloat = 0; 02187 } 02188 02189 /* this is an intersecting box; it has to jump through a few more hoops */ 02190 if (rb == res->parent || rb->parent.expansion_area == res->parent) 02191 return 0; /* don't see what we came from */ 02192 02193 /* if we are expanding a source edge, don't let other sources 02194 * or their expansions stop us. 02195 */ 02196 #if 1 02197 if (res->parent->flags.source) 02198 if (rb->flags.source 02199 || (rb->type == EXPANSION_AREA 02200 && rb->parent.expansion_area->flags.source)) 02201 return 0; 02202 #endif 02203 02204 /* we ignore via expansion boxes because maybe its 02205 * cheaper to get there without the via through 02206 * the path we're exploring now. 02207 */ 02208 if (rb->flags.is_via && rb->type == EXPANSION_AREA) 02209 return 0; 02210 02211 if (rb->type == PLANE) /* expanding inside a plane is not good */ 02212 { 02213 if (rbox.X1 < res->orig.X1 && rbox.X2 > res->orig.X2 && 02214 rbox.Y1 < res->orig.Y1 && rbox.Y2 > res->orig.Y2) 02215 { 02216 res->inflated = bloat_box (&res->orig, res->bloat); 02217 return 1; 02218 } 02219 } 02220 /* calculate the distances from original box to this blocker */ 02221 dn = de = ds = dw = 0; 02222 if (!(res->done & _NORTH) && rbox.Y1 <= res->orig.Y1 02223 && rbox.Y2 > res->inflated.Y1) 02224 dn = res->orig.Y1 - rbox.Y2; 02225 if (!(res->done & _EAST) && rbox.X2 >= res->orig.X2 02226 && rbox.X1 < res->inflated.X2) 02227 de = rbox.X1 - res->orig.X2; 02228 if (!(res->done & _SOUTH) && rbox.Y2 >= res->orig.Y2 02229 && rbox.Y1 < res->inflated.Y2) 02230 ds = rbox.Y1 - res->orig.Y2; 02231 if (!(res->done & _WEST) && rbox.X1 <= res->orig.X1 02232 && rbox.X2 > res->inflated.X1) 02233 dw = res->orig.X1 - rbox.X2; 02234 if (dn <= 0 && de <= 0 && ds <= 0 && dw <= 0) 02235 return 1; 02236 /* now shrink the inflated box to the largest blocking direction */ 02237 if (dn >= de && dn >= ds && dn >= dw) 02238 { 02239 res->inflated.Y1 = rbox.Y2 - bloat; 02240 res->n = rb; 02241 } 02242 else if (de >= ds && de >= dw) 02243 { 02244 res->inflated.X2 = rbox.X1 + bloat; 02245 res->e = rb; 02246 } 02247 else if (ds >= dw) 02248 { 02249 res->inflated.Y2 = rbox.Y1 + bloat; 02250 res->s = rb; 02251 } 02252 else 02253 { 02254 res->inflated.X1 = rbox.X2 - bloat; 02255 res->w = rb; 02256 } 02257 return 1; 02258 } 02259 02260 static bool 02261 boink_box (routebox_t * rb, struct E_result *res, direction_t dir) 02262 { 02263 Coord bloat; 02264 if (rb->style->Keepaway > res->keep) 02265 bloat = res->keep - rb->style->Keepaway; 02266 else 02267 bloat = 0; 02268 if (rb->flags.nobloat) 02269 bloat = res->bloat; 02270 switch (dir) 02271 { 02272 case NORTH: 02273 case SOUTH: 02274 if (rb->sbox.X2 <= res->inflated.X1 + bloat 02275 || rb->sbox.X1 >= res->inflated.X2 - bloat) 02276 return false; 02277 return true; 02278 case EAST: 02279 case WEST: 02280 if (rb->sbox.Y1 >= res->inflated.Y2 - bloat 02281 || rb->sbox.Y2 <= res->inflated.Y1 + bloat) 02282 return false; 02283 return true; 02284 break; 02285 default: 02286 assert (0); 02287 } 02288 return false; 02289 } 02290 02306 struct E_result * 02307 Expand (rtree_t * rtree, edge_t * e, const BoxType * box) 02308 { 02309 static struct E_result ans; 02310 int noshrink; /* bit field of which edges to not shrink */ 02311 02312 ans.bloat = AutoRouteParameters.bloat; 02313 ans.orig = *box; 02314 ans.n = ans.e = ans.s = ans.w = NULL; 02315 02316 /* the inflated box must be bloated in all directions that it might 02317 * hit something in order to guarantee that we see object in the 02318 * tree it might hit. The tree holds objects bloated by their own 02319 * keepaway so we are guaranteed to honor that. 02320 */ 02321 switch (e->expand_dir) 02322 { 02323 case ALL: 02324 ans.inflated.X1 = (e->rb->came_from == EAST ? ans.orig.X1 : 0); 02325 ans.inflated.Y1 = (e->rb->came_from == SOUTH ? ans.orig.Y1 : 0); 02326 ans.inflated.X2 = 02327 (e->rb->came_from == WEST ? ans.orig.X2 : PCB->MaxWidth); 02328 ans.inflated.Y2 = 02329 (e->rb->came_from == NORTH ? ans.orig.Y2 : PCB->MaxHeight); 02330 if (e->rb->came_from == NORTH) 02331 ans.done = noshrink = _SOUTH; 02332 else if (e->rb->came_from == EAST) 02333 ans.done = noshrink = _WEST; 02334 else if (e->rb->came_from == SOUTH) 02335 ans.done = noshrink = _NORTH; 02336 else if (e->rb->came_from == WEST) 02337 ans.done = noshrink = _EAST; 02338 else 02339 ans.done = noshrink = 0; 02340 break; 02341 case NORTH: 02342 ans.done = _SOUTH + _EAST + _WEST; 02343 noshrink = _SOUTH; 02344 ans.inflated.X1 = box->X1 - ans.bloat; 02345 ans.inflated.X2 = box->X2 + ans.bloat; 02346 ans.inflated.Y2 = box->Y2; 02347 ans.inflated.Y1 = 0; /* far north */ 02348 break; 02349 case NE: 02350 ans.done = _SOUTH + _WEST; 02351 noshrink = 0; 02352 ans.inflated.X1 = box->X1 - ans.bloat; 02353 ans.inflated.X2 = PCB->MaxWidth; 02354 ans.inflated.Y2 = box->Y2 + ans.bloat; 02355 ans.inflated.Y1 = 0; 02356 break; 02357 case EAST: 02358 ans.done = _NORTH + _SOUTH + _WEST; 02359 noshrink = _WEST; 02360 ans.inflated.Y1 = box->Y1 - ans.bloat; 02361 ans.inflated.Y2 = box->Y2 + ans.bloat; 02362 ans.inflated.X1 = box->X1; 02363 ans.inflated.X2 = PCB->MaxWidth; 02364 break; 02365 case SE: 02366 ans.done = _NORTH + _WEST; 02367 noshrink = 0; 02368 ans.inflated.X1 = box->X1 - ans.bloat; 02369 ans.inflated.X2 = PCB->MaxWidth; 02370 ans.inflated.Y2 = PCB->MaxHeight; 02371 ans.inflated.Y1 = box->Y1 - ans.bloat; 02372 break; 02373 case SOUTH: 02374 ans.done = _NORTH + _EAST + _WEST; 02375 noshrink = _NORTH; 02376 ans.inflated.X1 = box->X1 - ans.bloat; 02377 ans.inflated.X2 = box->X2 + ans.bloat; 02378 ans.inflated.Y1 = box->Y1; 02379 ans.inflated.Y2 = PCB->MaxHeight; 02380 break; 02381 case SW: 02382 ans.done = _NORTH + _EAST; 02383 noshrink = 0; 02384 ans.inflated.X1 = 0; 02385 ans.inflated.X2 = box->X2 + ans.bloat; 02386 ans.inflated.Y2 = PCB->MaxHeight; 02387 ans.inflated.Y1 = box->Y1 - ans.bloat; 02388 break; 02389 case WEST: 02390 ans.done = _NORTH + _SOUTH + _EAST; 02391 noshrink = _EAST; 02392 ans.inflated.Y1 = box->Y1 - ans.bloat; 02393 ans.inflated.Y2 = box->Y2 + ans.bloat; 02394 ans.inflated.X1 = 0; 02395 ans.inflated.X2 = box->X2; 02396 break; 02397 case NW: 02398 ans.done = _SOUTH + _EAST; 02399 noshrink = 0; 02400 ans.inflated.X1 = 0; 02401 ans.inflated.X2 = box->X2 + ans.bloat; 02402 ans.inflated.Y2 = box->Y2 + ans.bloat; 02403 ans.inflated.Y1 = 0; 02404 break; 02405 default: 02406 noshrink = ans.done = 0; 02407 assert (0); 02408 } 02409 ans.keep = e->rb->style->Keepaway; 02410 ans.parent = nonhomeless_parent (e->rb); 02411 r_search (rtree, &ans.inflated, NULL, __Expand_this_rect, &ans); 02412 /* because the overlaping boxes are found in random order, some blockers 02413 * may have limited edges prematurely, so we check if the blockers realy 02414 * are blocking, and make another try if not 02415 */ 02416 if (ans.n && !boink_box (ans.n, &ans, NORTH)) 02417 ans.inflated.Y1 = 0; 02418 else 02419 ans.done |= _NORTH; 02420 if (ans.e && !boink_box (ans.e, &ans, EAST)) 02421 ans.inflated.X2 = PCB->MaxWidth; 02422 else 02423 ans.done |= _EAST; 02424 if (ans.s && !boink_box (ans.s, &ans, SOUTH)) 02425 ans.inflated.Y2 = PCB->MaxHeight; 02426 else 02427 ans.done |= _SOUTH; 02428 if (ans.w && !boink_box (ans.w, &ans, WEST)) 02429 ans.inflated.X1 = 0; 02430 else 02431 ans.done |= _WEST; 02432 if (ans.done != _NORTH + _EAST + _SOUTH + _WEST) 02433 { 02434 r_search (rtree, &ans.inflated, NULL, __Expand_this_rect, &ans); 02435 } 02436 if ((noshrink & _NORTH) == 0) 02437 ans.inflated.Y1 += ans.bloat; 02438 if ((noshrink & _EAST) == 0) 02439 ans.inflated.X2 -= ans.bloat; 02440 if ((noshrink & _SOUTH) == 0) 02441 ans.inflated.Y2 -= ans.bloat; 02442 if ((noshrink & _WEST) == 0) 02443 ans.inflated.X1 += ans.bloat; 02444 return &ans; 02445 } 02446 02454 static int 02455 blocker_to_heap (heap_t * heap, routebox_t * rb, 02456 BoxType * box, direction_t dir) 02457 { 02458 BoxType b = rb->sbox; 02459 if (rb->style->Keepaway > AutoRouteParameters.style->Keepaway) 02460 b = 02461 bloat_box (&b, 02462 rb->style->Keepaway - AutoRouteParameters.style->Keepaway); 02463 b = clip_box (&b, box); 02464 assert (box_is_good (&b)); 02465 /* we want to look at the blockers clockwise around the box */ 02466 switch (dir) 02467 { 02468 /* we need to use the other coordinate fraction to resolve 02469 * ties since we want the shorter of the furthest 02470 * first. 02471 */ 02472 case NORTH: 02473 heap_insert (heap, b.X1 - b.X1 / (b.X2 + 1.0), rb); 02474 break; 02475 case EAST: 02476 heap_insert (heap, b.Y1 - b.Y1 / (b.Y2 + 1.0), rb); 02477 break; 02478 case SOUTH: 02479 heap_insert (heap, -(b.X2 + b.X1 / (b.X2 + 1.0)), rb); 02480 break; 02481 case WEST: 02482 heap_insert (heap, -(b.Y2 + b.Y1 / (b.Y2 + 1.0)), rb); 02483 break; 02484 default: 02485 assert (0); 02486 } 02487 if (rb->flags.fixed && !rb->flags.target && !rb->flags.source) 02488 return 1; 02489 return 0; 02490 } 02491 02497 static routebox_t * 02498 CreateBridge (const BoxType * area, routebox_t * parent, direction_t dir) 02499 { 02500 routebox_t *rb = (routebox_t *) malloc (sizeof (*rb)); 02501 memset ((void *) rb, 0, sizeof (*rb)); 02502 assert (area && parent); 02503 init_const_box (rb, area->X1, area->Y1, area->X2, area->Y2, 0); 02504 rb->group = parent->group; 02505 rb->type = EXPANSION_AREA; 02506 rb->came_from = dir; 02507 rb->cost_point = closest_point_in_box (&parent->cost_point, area); 02508 rb->cost = parent->cost + cost_to_point_on_layer (&parent->cost_point, 02509 &rb->cost_point, 02510 rb->group); 02511 rb->parent.expansion_area = route_parent (parent); 02512 if (rb->parent.expansion_area->flags.homeless) 02513 RB_up_count (rb->parent.expansion_area); 02514 rb->flags.homeless = 1; 02515 rb->flags.nobloat = 1; 02516 rb->style = parent->style; 02517 rb->conflicts_with = parent->conflicts_with; 02518 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EDGES) 02519 showroutebox (rb); 02520 #endif 02521 return rb; 02522 } 02523 02528 void 02529 moveable_edge (vector_t * result, const BoxType * box, direction_t dir, 02530 routebox_t * rb, 02531 routebox_t * blocker, edge_t * e, rtree_t * targets, 02532 struct routeone_state *s, rtree_t * tree, vector_t * area_vec) 02533 { 02534 BoxType b; 02535 assert (box_is_good (box)); 02536 b = *box; 02537 /* for the cardinal directions, move the box to overlap the 02538 * the parent by 1 unit. Corner expansions overlap more 02539 * and their starting boxes are pre-prepared. 02540 * Check if anything is headed off the board edges 02541 */ 02542 switch (dir) 02543 { 02544 default: 02545 break; 02546 case NORTH: 02547 b.Y2 = b.Y1; 02548 b.Y1--; 02549 if (b.Y1 <= AutoRouteParameters.bloat) 02550 return; /* off board edge */ 02551 break; 02552 case EAST: 02553 b.X1 = b.X2; 02554 b.X2++; 02555 if (b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat) 02556 return; /* off board edge */ 02557 break; 02558 case SOUTH: 02559 b.Y1 = b.Y2; 02560 b.Y2++; 02561 if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat) 02562 return; /* off board edge */ 02563 break; 02564 case WEST: 02565 b.X2 = b.X1; 02566 b.X1--; 02567 if (b.X1 <= AutoRouteParameters.bloat) 02568 return; /* off board edge */ 02569 break; 02570 case NE: 02571 if (b.Y1 <= AutoRouteParameters.bloat + 1 02572 && b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat - 1) 02573 return; /* off board edge */ 02574 if (b.Y1 <= AutoRouteParameters.bloat + 1) 02575 dir = EAST; /* north off board edge */ 02576 if (b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat - 1) 02577 dir = NORTH; /* east off board edge */ 02578 break; 02579 case SE: 02580 if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat - 1 02581 && b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat - 1) 02582 return; /* off board edge */ 02583 if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat - 1) 02584 dir = EAST; /* south off board edge */ 02585 if (b.X2 >= PCB->MaxWidth - AutoRouteParameters.bloat - 1) 02586 dir = SOUTH; /* east off board edge */ 02587 break; 02588 case SW: 02589 if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat - 1 02590 && b.X1 <= AutoRouteParameters.bloat + 1) 02591 return; /* off board edge */ 02592 if (b.Y2 >= PCB->MaxHeight - AutoRouteParameters.bloat - 1) 02593 dir = WEST; /* south off board edge */ 02594 if (b.X1 <= AutoRouteParameters.bloat + 1) 02595 dir = SOUTH; /* west off board edge */ 02596 break; 02597 case NW: 02598 if (b.Y1 <= AutoRouteParameters.bloat + 1 02599 && b.X1 <= AutoRouteParameters.bloat + 1) 02600 return; /* off board edge */ 02601 if (b.Y1 <= AutoRouteParameters.bloat + 1) 02602 dir = WEST; /* north off board edge */ 02603 if (b.X1 <= AutoRouteParameters.bloat + 1) 02604 dir = NORTH; /* west off board edge */ 02605 break; 02606 } 02607 02608 if (!blocker) 02609 { 02610 edge_t *ne; 02611 routebox_t *nrb = CreateBridge (&b, rb, dir); 02612 /* move the cost point in corner expansions 02613 * these boxes are bigger, so move close to the target 02614 */ 02615 if (dir == NE || dir == SE || dir == SW || dir == NW) 02616 { 02617 CheapPointType p; 02618 p = 02619 closest_point_in_box (&nrb->cost_point, &e->mincost_target->sbox); 02620 p = closest_point_in_box (&p, &b); 02621 nrb->cost += cost_to_point_on_layer (&p, &nrb->cost_point, 02622 nrb->group); 02623 nrb->cost_point = p; 02624 } 02625 ne = CreateEdge (nrb, nrb->cost_point.X, nrb->cost_point.Y, 02626 nrb->cost, NULL, dir, targets); 02627 vector_append (result, ne); 02628 } 02629 else if (AutoRouteParameters.with_conflicts && !blocker->flags.target 02630 && !blocker->flags.fixed && !blocker->flags.touched && 02631 !blocker->flags.source && blocker->type != EXPANSION_AREA) 02632 { 02633 edge_t *ne; 02634 routebox_t *nrb; 02635 /* make a bridge to the edge of the blocker 02636 * in all directions from there 02637 */ 02638 switch (dir) 02639 { 02640 case NORTH: 02641 b.Y1 = blocker->sbox.Y2 - 1; 02642 break; 02643 case EAST: 02644 b.X2 = blocker->sbox.X1 + 1; 02645 break; 02646 case SOUTH: 02647 b.Y2 = blocker->sbox.Y1 + 1; 02648 break; 02649 case WEST: 02650 b.X1 = blocker->sbox.X2 - 1; 02651 break; 02652 default: 02653 assert (0); 02654 } 02655 if (!box_is_good (&b)) 02656 return; /* how did this happen ? */ 02657 nrb = CreateBridge (&b, rb, dir); 02658 r_insert_entry (tree, &nrb->box, 1); 02659 vector_append (area_vec, nrb); 02660 nrb->flags.homeless = 0; /* not homeless any more */ 02661 /* mark this one as conflicted */ 02662 path_conflicts (nrb, blocker, true); 02663 /* and make an expansion edge */ 02664 nrb->cost_point = 02665 closest_point_in_box (&nrb->cost_point, &blocker->sbox); 02666 nrb->cost += 02667 cost_to_point_on_layer (&nrb->parent.expansion_area->cost_point, 02668 &nrb->cost_point, 02669 nrb->group) * CONFLICT_PENALTY (blocker); 02670 02671 ne = CreateEdge (nrb, nrb->cost_point.X, nrb->cost_point.Y, nrb->cost, 02672 NULL, ALL, targets); 02673 ne->flags.is_interior = 1; 02674 vector_append (result, ne); 02675 } 02676 #if 1 02677 else if (blocker->type == EXPANSION_AREA) 02678 { 02679 if (blocker->cost < rb->cost || blocker->cost <= rb->cost + 02680 cost_to_point_on_layer (&blocker->cost_point, &rb->cost_point, 02681 rb->group)) 02682 return; 02683 if (blocker->conflicts_with || rb->conflicts_with) 02684 return; 02685 /* does the blocker overlap this routebox ?? */ 02686 /* does this re-parenting operation leave a memory leak? */ 02687 if (blocker->parent.expansion_area->flags.homeless) 02688 RB_down_count (blocker->parent.expansion_area); 02689 blocker->parent.expansion_area = rb; 02690 return; 02691 } 02692 #endif 02693 else if (blocker->flags.target) 02694 { 02695 routebox_t *nrb; 02696 edge_t *ne; 02697 b = bloat_box (&b, 1); 02698 if (!box_intersect (&b, &blocker->sbox)) 02699 { 02700 /* if the expansion edge stopped before touching, expand the bridge */ 02701 switch (dir) 02702 { 02703 case NORTH: 02704 b.Y1 -= AutoRouteParameters.bloat + 1; 02705 break; 02706 case EAST: 02707 b.X2 += AutoRouteParameters.bloat + 1; 02708 break; 02709 case SOUTH: 02710 b.Y2 += AutoRouteParameters.bloat + 1; 02711 break; 02712 case WEST: 02713 b.X1 -= AutoRouteParameters.bloat + 1; 02714 break; 02715 default: 02716 assert (0); 02717 } 02718 } 02719 assert (box_intersect (&b, &blocker->sbox)); 02720 b = shrink_box (&b, 1); 02721 nrb = CreateBridge (&b, rb, dir); 02722 r_insert_entry (tree, &nrb->box, 1); 02723 vector_append (area_vec, nrb); 02724 nrb->flags.homeless = 0; /* not homeless any more */ 02725 ne = CreateEdge (nrb, nrb->cost_point.X, nrb->cost_point.Y, 02726 nrb->cost, blocker, dir, NULL); 02727 best_path_candidate (s, ne, blocker); 02728 DestroyEdge (&ne); 02729 } 02730 } 02731 02732 struct break_info 02733 { 02734 heap_t *heap; 02735 routebox_t *parent; 02736 BoxType box; 02737 direction_t dir; 02738 bool ignore_source; 02739 }; 02740 02741 static int 02742 __GatherBlockers (const BoxType * box, void *cl) 02743 { 02744 routebox_t *rb = (routebox_t *) box; 02745 struct break_info *bi = (struct break_info *) cl; 02746 BoxType b; 02747 02748 if (bi->parent == rb || rb->flags.touched || 02749 bi->parent->parent.expansion_area == rb) 02750 return 0; 02751 if (rb->flags.source && bi->ignore_source) 02752 return 0; 02753 b = rb->sbox; 02754 if (rb->style->Keepaway > AutoRouteParameters.style->Keepaway) 02755 b = 02756 bloat_box (&b, 02757 rb->style->Keepaway - AutoRouteParameters.style->Keepaway); 02758 if (b.X2 <= bi->box.X1 || b.X1 >= bi->box.X2 02759 || b.Y1 >= bi->box.Y2 || b.Y2 <= bi->box.Y1) 02760 return 0; 02761 return blocker_to_heap (bi->heap, rb, &bi->box, bi->dir); 02762 } 02763 02769 static inline BoxType 02770 previous_edge (Coord last, direction_t i, const BoxType * b) 02771 { 02772 BoxType db = *b; 02773 switch (i) 02774 { 02775 case EAST: 02776 db.X1 = last; 02777 break; 02778 case SOUTH: 02779 db.Y1 = last; 02780 break; 02781 case WEST: 02782 db.X2 = last; 02783 break; 02784 default: 02785 Message ("previous edge bogus direction!"); 02786 assert (0); 02787 } 02788 return db; 02789 } 02790 02796 vector_t * 02797 BreakManyEdges (struct routeone_state * s, rtree_t * targets, rtree_t * tree, 02798 vector_t * area_vec, struct E_result * ans, routebox_t * rb, 02799 edge_t * e) 02800 { 02801 struct break_info bi; 02802 vector_t *edges; 02803 heap_t *heap[4]; 02804 Coord first, last; 02805 Coord bloat; 02806 direction_t dir; 02807 routebox_t fake; 02808 02809 edges = vector_create (); 02810 bi.ignore_source = rb->parent.expansion_area->flags.source; 02811 bi.parent = rb; 02812 /* we add 2 to the bloat. 02813 * 1 will get us to the actual blocker that Expand() hit 02814 * but 1 more is needed because the new expansion edges 02815 * move out by 1 so they don't overlap their parents 02816 * this extra expansion could "trap" the edge if 02817 * there is a blocker 2 units from the original rb, 02818 * it is 1 unit from the new expansion edge which 02819 * would prevent expansion. So we want to break the 02820 * edge on it now to avoid the trap. 02821 */ 02822 02823 bloat = AutoRouteParameters.bloat + 2; 02824 /* for corner expansion, we need to have a fake blocker 02825 * to prevent expansion back where we came from since 02826 * we still need to break portions of all 4 edges 02827 */ 02828 if (e->expand_dir == NE || e->expand_dir == SE || 02829 e->expand_dir == SW || e->expand_dir == NW) 02830 { 02831 BoxType *fb = (BoxType *) &fake.sbox; 02832 memset (&fake, 0, sizeof (fake)); 02833 *fb = e->rb->sbox; 02834 fake.flags.fixed = 1; /* this stops expansion there */ 02835 fake.type = LINE; 02836 fake.style = AutoRouteParameters.style; 02837 #ifndef NDEBUG 02838 /* the routbox_is_good checker wants a lot more! */ 02839 fake.flags.inited = 1; 02840 fb = (BoxType *) &fake.box; 02841 *fb = e->rb->sbox; 02842 fake.same_net.next = fake.same_net.prev = &fake; 02843 fake.same_subnet.next = fake.same_subnet.prev = &fake; 02844 fake.original_subnet.next = fake.original_subnet.prev = &fake; 02845 fake.different_net.next = fake.different_net.prev = &fake; 02846 #endif 02847 } 02848 /* gather all of the blockers in heaps so they can be accessed 02849 * in clockwise order, which allows finding corners that can 02850 * be expanded. 02851 */ 02852 for (dir = NORTH; dir <= WEST; dir = directionIncrement(dir)) 02853 { 02854 /* don't break the edge we came from */ 02855 if (e->expand_dir != ((dir + 2) % 4)) 02856 { 02857 heap[dir] = heap_create (); 02858 bi.box = bloat_box (&rb->sbox, bloat); 02859 bi.heap = heap[dir]; 02860 bi.dir = dir; 02861 /* convert to edge */ 02862 switch (dir) 02863 { 02864 case NORTH: 02865 bi.box.Y2 = bi.box.Y1 + bloat + 1; 02866 /* for corner expansion, block the start edges and 02867 * limit the blocker search to only the new edge segment 02868 */ 02869 if (e->expand_dir == SE || e->expand_dir == SW) 02870 blocker_to_heap (heap[dir], &fake, &bi.box, dir); 02871 if (e->expand_dir == SE) 02872 bi.box.X1 = e->rb->sbox.X2; 02873 if (e->expand_dir == SW) 02874 bi.box.X2 = e->rb->sbox.X1; 02875 rb->n = r_search (tree, &bi.box, NULL, __GatherBlockers, &bi); 02876 break; 02877 case EAST: 02878 bi.box.X1 = bi.box.X2 - bloat - 1; 02879 /* corner, same as above */ 02880 if (e->expand_dir == SW || e->expand_dir == NW) 02881 blocker_to_heap (heap[dir], &fake, &bi.box, dir); 02882 if (e->expand_dir == SW) 02883 bi.box.Y1 = e->rb->sbox.Y2; 02884 if (e->expand_dir == NW) 02885 bi.box.Y2 = e->rb->sbox.Y1; 02886 rb->e = r_search (tree, &bi.box, NULL, __GatherBlockers, &bi); 02887 break; 02888 case SOUTH: 02889 bi.box.Y1 = bi.box.Y2 - bloat - 1; 02890 /* corner, same as above */ 02891 if (e->expand_dir == NE || e->expand_dir == NW) 02892 blocker_to_heap (heap[dir], &fake, &bi.box, dir); 02893 if (e->expand_dir == NE) 02894 bi.box.X1 = e->rb->sbox.X2; 02895 if (e->expand_dir == NW) 02896 bi.box.X2 = e->rb->sbox.X1; 02897 rb->s = r_search (tree, &bi.box, NULL, __GatherBlockers, &bi); 02898 break; 02899 case WEST: 02900 bi.box.X2 = bi.box.X1 + bloat + 1; 02901 /* corner, same as above */ 02902 if (e->expand_dir == NE || e->expand_dir == SE) 02903 blocker_to_heap (heap[dir], &fake, &bi.box, dir); 02904 if (e->expand_dir == SE) 02905 bi.box.Y1 = e->rb->sbox.Y2; 02906 if (e->expand_dir == NE) 02907 bi.box.Y2 = e->rb->sbox.Y1; 02908 rb->w = r_search (tree, &bi.box, NULL, __GatherBlockers, &bi); 02909 break; 02910 default: 02911 assert (0); 02912 } 02913 } 02914 else 02915 heap[dir] = NULL; 02916 } 02917 #if 1 02918 rb->cost += 02919 (rb->n + rb->e + rb->s + 02920 rb->w) * AutoRouteParameters.CongestionPenalty / box_area (rb->sbox); 02921 #endif 02922 /* now handle the blockers: 02923 * Go around the expansion area clockwise (North->East->South->West) 02924 * pulling blockers from the heap (which makes them come out in the right 02925 * order). Break the edges on the blocker and make the segments and corners 02926 * moveable as possible. 02927 */ 02928 first = last = -1; 02929 for (dir = NORTH; dir <= WEST; dir = directionIncrement(dir)) 02930 { 02931 if (heap[dir] && !heap_is_empty (heap[dir])) 02932 { 02933 /* pull the very first one out of the heap outside of the 02934 * heap loop because it is special; it can be part of a corner 02935 */ 02936 routebox_t *blk = (routebox_t *) heap_remove_smallest (heap[dir]); 02937 BoxType b = rb->sbox; 02938 struct broken_boxes broke = break_box_edge (&b, dir, blk); 02939 if (broke.is_valid_left) 02940 { 02941 /* if last > 0, then the previous edge had a segment 02942 * joining this one, so it forms a valid corner expansion 02943 */ 02944 if (last > 0) 02945 { 02946 /* make a corner expansion */ 02947 BoxType db = b; 02948 switch (dir) 02949 { 02950 case EAST: 02951 /* possible NE expansion */ 02952 db.X1 = last; 02953 db.Y2 = MIN (db.Y2, broke.left.Y2); 02954 break; 02955 case SOUTH: 02956 /* possible SE expansion */ 02957 db.Y1 = last; 02958 db.X1 = MAX (db.X1, broke.left.X1); 02959 break; 02960 case WEST: 02961 /* possible SW expansion */ 02962 db.X2 = last; 02963 db.Y1 = MAX (db.Y1, broke.left.Y1); 02964 break; 02965 default: 02966 assert (0); 02967 break; 02968 } 02969 moveable_edge (edges, &db, (direction_t)(dir + 3), rb, NULL, e, targets, 02970 s, NULL, NULL); 02971 } 02972 else if (dir == NORTH) /* north is start, so nothing "before" it */ 02973 { 02974 /* save for a possible corner once we've 02975 * finished circling the box 02976 */ 02977 first = MAX (b.X1, broke.left.X2); 02978 } 02979 else 02980 { 02981 /* this is just a boring straight expansion 02982 * since the orthogonal segment was blocked 02983 */ 02984 moveable_edge (edges, &broke.left, dir, rb, NULL, e, 02985 targets, s, NULL, NULL); 02986 } 02987 } /* broke.is_valid_left */ 02988 else if (last > 0) 02989 { 02990 /* if the last one didn't become a corner, 02991 * we still want to expand it straight out 02992 * in the direction of the previous edge, 02993 * which it belongs to. 02994 */ 02995 BoxType db = previous_edge (last, dir, &rb->sbox); 02996 moveable_edge (edges, &db, (direction_t)(dir - 1), rb, NULL, e, targets, s, 02997 NULL, NULL); 02998 } 02999 if (broke.is_valid_center && !blk->flags.source) 03000 moveable_edge (edges, &broke.center, dir, rb, blk, e, targets, s, 03001 tree, area_vec); 03002 /* this is the heap extraction loop. We break out 03003 * if there's nothing left in the heap, but if we * are blocked all the way to the far edge, we can 03004 * just leave stuff in the heap when it is destroyed 03005 */ 03006 while (broke.is_valid_right) 03007 { 03008 /* move the box edge to the next potential free point */ 03009 switch (dir) 03010 { 03011 case NORTH: 03012 last = b.X1 = MAX (broke.right.X1, b.X1); 03013 break; 03014 case EAST: 03015 last = b.Y1 = MAX (broke.right.Y1, b.Y1); 03016 break; 03017 case SOUTH: 03018 last = b.X2 = MIN (broke.right.X2, b.X2); 03019 break; 03020 case WEST: 03021 last = b.Y2 = MIN (broke.right.Y2, b.Y2); 03022 break; 03023 default: 03024 assert (0); 03025 } 03026 if (heap_is_empty (heap[dir])) 03027 break; 03028 blk = (routebox_t *)heap_remove_smallest (heap[dir]); 03029 broke = break_box_edge (&b, dir, blk); 03030 if (broke.is_valid_left) 03031 moveable_edge (edges, &broke.left, dir, rb, NULL, e, targets, 03032 s, NULL, NULL); 03033 if (broke.is_valid_center && !blk->flags.source) 03034 moveable_edge (edges, &broke.center, dir, rb, blk, e, targets, 03035 s, tree, area_vec); 03036 } 03037 if (!broke.is_valid_right) 03038 last = -1; 03039 } 03040 else /* if (heap[dir]) */ 03041 { 03042 /* nothing touched this edge! Expand the whole edge unless 03043 * (1) it hit the board edge or (2) was the source of our expansion 03044 * 03045 * for this case (of hitting nothing) we give up trying for corner 03046 * expansions because it is likely that they're not possible anyway 03047 */ 03048 if ((e->expand_dir == ALL ? e->rb->came_from : e->expand_dir) != 03049 ((dir + 2) % 4)) 03050 { 03051 /* ok, we are not going back on ourselves, and the whole edge seems free */ 03052 moveable_edge (edges, &rb->sbox, dir, rb, NULL, e, targets, s, 03053 NULL, NULL); 03054 } 03055 03056 if (last > 0) 03057 { 03058 /* expand the leftover from the prior direction */ 03059 BoxType db = previous_edge (last, dir, &rb->sbox); 03060 moveable_edge (edges, &db, (direction_t)(dir - 1), rb, NULL, e, targets, s, 03061 NULL, NULL); 03062 } 03063 last = -1; 03064 } 03065 } /* for loop */ 03066 /* finally, check for the NW corner now that we've come full circle */ 03067 if (first > 0 && last > 0) 03068 { 03069 BoxType db = rb->sbox; 03070 db.X2 = first; 03071 db.Y2 = last; 03072 moveable_edge (edges, &db, NW, rb, NULL, e, targets, s, NULL, NULL); 03073 } 03074 else 03075 { 03076 if (first > 0) 03077 { 03078 BoxType db = rb->sbox; 03079 db.X2 = first; 03080 moveable_edge (edges, &db, NORTH, rb, NULL, e, targets, s, NULL, 03081 NULL); 03082 } 03083 else if (last > 0) 03084 { 03085 BoxType db = rb->sbox; 03086 db.Y2 = last; 03087 moveable_edge (edges, &db, WEST, rb, NULL, e, targets, s, NULL, 03088 NULL); 03089 } 03090 } 03091 /* done with all expansion edges of this box */ 03092 for (dir = NORTH; dir <= WEST; dir = directionIncrement(dir)) 03093 { 03094 if (heap[dir]) 03095 heap_destroy (&heap[dir]); 03096 } 03097 return edges; 03098 } 03099 03100 static routebox_t * 03101 rb_source (routebox_t * rb) 03102 { 03103 while (rb && !rb->flags.source) 03104 { 03105 assert (rb->type == EXPANSION_AREA); 03106 rb = rb->parent.expansion_area; 03107 } 03108 assert (rb); 03109 return rb; 03110 } 03111 03112 /* ------------ */ 03113 03114 struct foib_info 03115 { 03116 const BoxType *box; 03117 routebox_t *intersect; 03118 jmp_buf env; 03119 }; 03120 03121 static int 03122 foib_rect_in_reg (const BoxType * box, void *cl) 03123 { 03124 struct foib_info *foib = (struct foib_info *) cl; 03125 BoxType rbox; 03126 routebox_t *rb = (routebox_t *) box; 03127 if (rb->flags.touched) 03128 return 0; 03129 // if (rb->type == EXPANSION_AREA && !rb->flags.is_via) 03130 // return 0; 03131 rbox = bloat_routebox (rb); 03132 if (!box_intersect (&rbox, foib->box)) 03133 return 0; 03134 /* this is an intersector! */ 03135 foib->intersect = (routebox_t *) box; 03136 longjmp (foib->env, 1); /* skip to the end! */ 03137 return 1; 03138 } 03139 static routebox_t * 03140 FindOneInBox (rtree_t * rtree, routebox_t * rb) 03141 { 03142 struct foib_info foib; 03143 BoxType r; 03144 03145 r = rb->sbox; 03146 foib.box = &r; 03147 foib.intersect = NULL; 03148 03149 if (setjmp (foib.env) == 0) 03150 r_search (rtree, &r, NULL, foib_rect_in_reg, &foib); 03151 return foib.intersect; 03152 } 03153 03154 struct therm_info 03155 { 03156 routebox_t *plane; 03157 BoxType query; 03158 jmp_buf env; 03159 }; 03160 static int 03161 ftherm_rect_in_reg (const BoxType * box, void *cl) 03162 { 03163 routebox_t *rbox = (routebox_t *) box; 03164 struct therm_info *ti = (struct therm_info *) cl; 03165 BoxType sq, sb; 03166 03167 if (rbox->type != PIN && rbox->type != VIA && rbox->type != VIA_SHADOW) 03168 return 0; 03169 if (rbox->group != ti->plane->group) 03170 return 0; 03171 03172 sb = shrink_routebox (rbox); 03173 switch (rbox->type) 03174 { 03175 case PIN: 03176 sq = shrink_box (&ti->query, rbox->parent.pin->Thickness); 03177 if (!box_intersect (&sb, &sq)) 03178 return 0; 03179 sb.X1 = rbox->parent.pin->X; 03180 sb.Y1 = rbox->parent.pin->Y; 03181 break; 03182 case VIA: 03183 if (rbox->flags.fixed) 03184 { 03185 sq = shrink_box (&ti->query, rbox->parent.via->Thickness); 03186 sb.X1 = rbox->parent.pin->X; 03187 sb.Y1 = rbox->parent.pin->Y; 03188 } 03189 else 03190 { 03191 sq = shrink_box (&ti->query, rbox->style->Diameter); 03192 sb.X1 = CENTER_X (sb); 03193 sb.Y1 = CENTER_Y (sb); 03194 } 03195 if (!box_intersect (&sb, &sq)) 03196 return 0; 03197 break; 03198 case VIA_SHADOW: 03199 sq = shrink_box (&ti->query, rbox->style->Diameter); 03200 if (!box_intersect (&sb, &sq)) 03201 return 0; 03202 sb.X1 = CENTER_X (sb); 03203 sb.Y1 = CENTER_Y (sb); 03204 break; 03205 default: 03206 assert (0); 03207 } 03208 ti->plane = rbox; 03209 longjmp (ti->env, 1); 03210 return 1; 03211 } 03212 03217 routebox_t * 03218 FindThermable (rtree_t * rtree, routebox_t * rb) 03219 { 03220 struct therm_info info; 03221 03222 info.plane = rb; 03223 info.query = shrink_routebox (rb); 03224 03225 if (setjmp (info.env) == 0) 03226 { 03227 r_search (rtree, &info.query, NULL, ftherm_rect_in_reg, &info); 03228 return NULL; 03229 } 03230 return info.plane; 03231 } 03232 03237 static void 03238 RD_DrawThermal (routedata_t * rd, Coord X, Coord Y, 03239 Cardinal group, Cardinal layer, routebox_t * subnet, 03240 bool is_bad) 03241 { 03242 routebox_t *rb; 03243 rb = (routebox_t *) malloc (sizeof (*rb)); 03244 memset ((void *) rb, 0, sizeof (*rb)); 03245 init_const_box (rb, X, Y, X + 1, Y + 1, 0); 03246 rb->group = group; 03247 rb->layer = layer; 03248 rb->flags.fixed = 0; 03249 rb->flags.is_bad = is_bad; 03250 rb->flags.is_odd = AutoRouteParameters.is_odd; 03251 rb->flags.circular = 0; 03252 rb->style = AutoRouteParameters.style; 03253 rb->type = THERMAL; 03254 InitLists (rb); 03255 MergeNets (rb, subnet, NET); 03256 MergeNets (rb, subnet, SUBNET); 03257 /* add it to the r-tree, this may be the whole route! */ 03258 r_insert_entry (rd->layergrouptree[rb->group], &rb->box, 1); 03259 rb->flags.homeless = 0; 03260 } 03261 03262 static void 03263 RD_DrawVia (routedata_t * rd, Coord X, Coord Y, 03264 Coord radius, routebox_t * subnet, bool is_bad) 03265 { 03266 routebox_t *rb, *first_via = NULL; 03267 int i; 03268 int ka = AutoRouteParameters.style->Keepaway; 03269 PinType *live_via = NULL; 03270 03271 if (TEST_FLAG (LIVEROUTEFLAG, PCB)) 03272 { 03273 live_via = CreateNewVia (PCB->Data, X, Y, radius * 2, 03274 2 * AutoRouteParameters.style->Keepaway, 0, 03275 AutoRouteParameters.style->Hole, NULL, 03276 MakeFlags (0)); 03277 if (live_via != NULL) 03278 DrawVia (live_via); 03279 } 03280 03281 /* a via cuts through every layer group */ 03282 for (i = 0; i < max_group; i++) 03283 { 03284 if (!is_layer_group_active[i]) 03285 continue; 03286 rb = (routebox_t *) malloc (sizeof (*rb)); 03287 memset ((void *) rb, 0, sizeof (*rb)); 03288 init_const_box (rb, 03289 /*X1 */ X - radius, /*Y1 */ Y - radius, 03290 /*X2 */ X + radius + 1, /*Y2 */ Y + radius + 1, ka); 03291 rb->group = i; 03292 rb->flags.fixed = 0; /* indicates that not on PCB yet */ 03293 rb->flags.is_odd = AutoRouteParameters.is_odd; 03294 rb->flags.is_bad = is_bad; 03295 rb->came_from = ALL; 03296 rb->flags.circular = true; 03297 rb->style = AutoRouteParameters.style; 03298 rb->pass = AutoRouteParameters.pass; 03299 if (first_via == NULL) 03300 { 03301 rb->type = VIA; 03302 rb->parent.via = NULL; /* indicates that not on PCB yet */ 03303 first_via = rb; 03304 /* only add the first via to mtspace, not the shadows too */ 03305 mtspace_add (rd->mtspace, &rb->box, rb->flags.is_odd ? ODD : EVEN, 03306 rb->style->Keepaway); 03307 } 03308 else 03309 { 03310 rb->type = VIA_SHADOW; 03311 rb->parent.via_shadow = first_via; 03312 } 03313 InitLists (rb); 03314 /* add these to proper subnet. */ 03315 MergeNets (rb, subnet, NET); 03316 MergeNets (rb, subnet, SUBNET); 03317 assert (__routebox_is_good (rb)); 03318 /* and add it to the r-tree! */ 03319 r_insert_entry (rd->layergrouptree[rb->group], &rb->box, 1); 03320 rb->flags.homeless = 0; /* not homeless anymore */ 03321 rb->livedraw_obj.via = live_via; 03322 } 03323 } 03324 static void 03325 RD_DrawLine (routedata_t * rd, 03326 Coord X1, Coord Y1, Coord X2, 03327 Coord Y2, Coord halfthick, Cardinal group, 03328 routebox_t * subnet, bool is_bad, bool is_45) 03329 { 03330 /* we hold the line in a queue to concatenate segments that 03331 * ajoin one another. That reduces the number of things in 03332 * the trees and allows conflict boxes to be larger, both of 03333 * which are really useful. 03334 */ 03335 static Coord qX1 = -1, qY1, qX2, qY2; 03336 static Coord qhthick; 03337 static Cardinal qgroup; 03338 static bool qis_45, qis_bad; 03339 static routebox_t *qsn; 03340 03341 routebox_t *rb; 03342 Coord ka = AutoRouteParameters.style->Keepaway; 03343 03344 /* don't draw zero-length segments. */ 03345 if (X1 == X2 && Y1 == Y2) 03346 return; 03347 if (qX1 == -1) /* first ever */ 03348 { 03349 qX1 = X1; 03350 qY1 = Y1; 03351 qX2 = X2; 03352 qY2 = Y2; 03353 qhthick = halfthick; 03354 qgroup = group; 03355 qis_45 = is_45; 03356 qis_bad = is_bad; 03357 qsn = subnet; 03358 return; 03359 } 03360 /* Check if the lines concatenat. We only check the 03361 * normal expected nextpoint=lastpoint condition 03362 */ 03363 if (X1 == qX2 && Y1 == qY2 && qhthick == halfthick && qgroup == group) 03364 { 03365 if (qX1 == qX2 && X1 == X2) /* everybody on the same X here */ 03366 { 03367 qY2 = Y2; 03368 return; 03369 } 03370 if (qY1 == qY2 && Y1 == Y2) /* same Y all around */ 03371 { 03372 qX2 = X2; 03373 return; 03374 } 03375 } 03376 /* dump the queue, no match here */ 03377 if (qX1 == -1) 03378 return; /* but not this! */ 03379 rb = (routebox_t *) malloc (sizeof (*rb)); 03380 memset ((void *) rb, 0, sizeof (*rb)); 03381 assert (is_45 ? (ABS (qX2 - qX1) == ABS (qY2 - qY1)) /* line must be 45-degrees */ 03382 : (qX1 == qX2 || qY1 == qY2) /* line must be ortho */ ); 03383 init_const_box (rb, 03384 /*X1 */ MIN (qX1, qX2) - qhthick, 03385 /*Y1 */ MIN (qY1, qY2) - qhthick, 03386 /*X2 */ MAX (qX1, qX2) + qhthick + 1, 03387 /*Y2 */ MAX (qY1, qY2) + qhthick + 1, ka); 03388 rb->group = qgroup; 03389 rb->type = LINE; 03390 rb->parent.line = NULL; /* indicates that not on PCB yet */ 03391 rb->flags.fixed = 0; /* indicates that not on PCB yet */ 03392 rb->flags.is_odd = AutoRouteParameters.is_odd; 03393 rb->flags.is_bad = qis_bad; 03394 rb->came_from = ALL; 03395 rb->flags.homeless = 0; /* we're putting this in the tree */ 03396 rb->flags.nonstraight = qis_45; 03397 rb->flags.bl_to_ur = ((qX2 >= qX1 && qY2 <= qY1) 03398 || (qX2 <= qX1 && qY2 >= qY1)); 03399 rb->style = AutoRouteParameters.style; 03400 rb->pass = AutoRouteParameters.pass; 03401 InitLists (rb); 03402 /* add these to proper subnet. */ 03403 MergeNets (rb, qsn, NET); 03404 MergeNets (rb, qsn, SUBNET); 03405 assert (__routebox_is_good (rb)); 03406 /* and add it to the r-tree! */ 03407 r_insert_entry (rd->layergrouptree[rb->group], &rb->box, 1); 03408 03409 if (TEST_FLAG (LIVEROUTEFLAG, PCB)) 03410 { 03411 LayerType *layer = LAYER_PTR (PCB->LayerGroups.Entries[rb->group][0]); 03412 LineType *line = CreateNewLineOnLayer (layer, qX1, qY1, qX2, qY2, 03413 2 * qhthick, 0, MakeFlags (0)); 03414 rb->livedraw_obj.line = line; 03415 if (line != NULL) 03416 DrawLine (layer, line); 03417 } 03418 03419 /* and to the via space structures */ 03420 if (AutoRouteParameters.use_vias) 03421 mtspace_add (rd->mtspace, &rb->box, rb->flags.is_odd ? ODD : EVEN, 03422 rb->style->Keepaway); 03423 usedGroup[rb->group] = true; 03424 /* and queue this one */ 03425 qX1 = X1; 03426 qY1 = Y1; 03427 qX2 = X2; 03428 qY2 = Y2; 03429 qhthick = halfthick; 03430 qgroup = group; 03431 qis_45 = is_45; 03432 qis_bad = is_bad; 03433 qsn = subnet; 03434 } 03435 03436 static bool 03437 RD_DrawManhattanLine (routedata_t * rd, 03438 const BoxType * box1, const BoxType * box2, 03439 CheapPointType start, CheapPointType end, 03440 Coord halfthick, Cardinal group, 03441 routebox_t * subnet, bool is_bad, bool last_was_x) 03442 { 03443 CheapPointType knee = start; 03444 if (end.X == start.X) 03445 { 03446 RD_DrawLine (rd, start.X, start.Y, end.X, end.Y, halfthick, group, 03447 subnet, is_bad, false); 03448 return false; 03449 } 03450 else if (end.Y == start.Y) 03451 { 03452 RD_DrawLine (rd, start.X, start.Y, end.X, end.Y, halfthick, group, 03453 subnet, is_bad, false); 03454 return true; 03455 } 03456 /* find where knee belongs */ 03457 if (point_in_box (box1, end.X, start.Y) 03458 || point_in_box (box2, end.X, start.Y)) 03459 { 03460 knee.X = end.X; 03461 knee.Y = start.Y; 03462 } 03463 else 03464 { 03465 knee.X = start.X; 03466 knee.Y = end.Y; 03467 } 03468 if ((knee.X == end.X && !last_was_x) && 03469 (point_in_box (box1, start.X, end.Y) 03470 || point_in_box (box2, start.X, end.Y))) 03471 { 03472 knee.X = start.X; 03473 knee.Y = end.Y; 03474 } 03475 assert (AutoRouteParameters.is_smoothing 03476 || point_in_closed_box (box1, knee.X, knee.Y) 03477 || point_in_closed_box (box2, knee.X, knee.Y)); 03478 03479 if (1 || !AutoRouteParameters.is_smoothing) 03480 { 03481 /* draw standard manhattan paths */ 03482 RD_DrawLine (rd, start.X, start.Y, knee.X, knee.Y, halfthick, group, 03483 subnet, is_bad, false); 03484 RD_DrawLine (rd, knee.X, knee.Y, end.X, end.Y, halfthick, group, 03485 subnet, is_bad, false); 03486 } 03487 else 03488 { 03489 /* draw 45-degree path across knee */ 03490 Coord len45 = MIN (ABS (start.X - end.X), ABS (start.Y - end.Y)); 03491 CheapPointType kneestart = knee, kneeend = knee; 03492 if (kneestart.X == start.X) 03493 kneestart.Y += (kneestart.Y > start.Y) ? -len45 : len45; 03494 else 03495 kneestart.X += (kneestart.X > start.X) ? -len45 : len45; 03496 if (kneeend.X == end.X) 03497 kneeend.Y += (kneeend.Y > end.Y) ? -len45 : len45; 03498 else 03499 kneeend.X += (kneeend.X > end.X) ? -len45 : len45; 03500 RD_DrawLine (rd, start.X, start.Y, kneestart.X, kneestart.Y, halfthick, 03501 group, subnet, is_bad, false); 03502 RD_DrawLine (rd, kneestart.X, kneestart.Y, kneeend.X, kneeend.Y, 03503 halfthick, group, subnet, is_bad, true); 03504 RD_DrawLine (rd, kneeend.X, kneeend.Y, end.X, end.Y, halfthick, group, 03505 subnet, is_bad, false); 03506 } 03507 return (knee.X != end.X); 03508 } 03509 03510 /* for smoothing, don't pack traces to min clearance gratuitously */ 03511 #if 0 03512 static void 03513 add_clearance (CheapPointType * nextpoint, const BoxType * b) 03514 { 03515 if (nextpoint->X == b->X1) 03516 { 03517 if (nextpoint->X + 03518 AutoRouteParameters.style->Keepaway < (b->X1 + b->X2) / 2) 03519 nextpoint->X += AutoRouteParameters.style->Keepaway; 03520 else 03521 nextpoint->X = (b->X1 + b->X2) / 2; 03522 } 03523 else if (nextpoint->X == b->X2) 03524 { 03525 if (nextpoint->X - 03526 AutoRouteParameters.style->Keepaway > (b->X1 + b->X2) / 2) 03527 nextpoint->X -= AutoRouteParameters.style->Keepaway; 03528 else 03529 nextpoint->X = (b->X1 + b->X2) / 2; 03530 } 03531 else if (nextpoint->Y == b->Y1) 03532 { 03533 if (nextpoint->Y + 03534 AutoRouteParameters.style->Keepaway < (b->Y1 + b->Y2) / 2) 03535 nextpoint->Y += AutoRouteParameters.style->Keepaway; 03536 else 03537 nextpoint->Y = (b->Y1 + b->Y2) / 2; 03538 } 03539 else if (nextpoint->Y == b->Y2) 03540 { 03541 if (nextpoint->Y - 03542 AutoRouteParameters.style->Keepaway > (b->Y1 + b->Y2) / 2) 03543 nextpoint->Y -= AutoRouteParameters.style->Keepaway; 03544 else 03545 nextpoint->Y = (b->Y1 + b->Y2) / 2; 03546 } 03547 } 03548 #endif 03549 03564 static void 03565 TracePath (routedata_t * rd, routebox_t * path, const routebox_t * target, 03566 routebox_t * subnet, bool is_bad) 03567 { 03568 bool last_x = false; 03569 Coord halfwidth = HALF_THICK (AutoRouteParameters.style->Thick); 03570 Coord radius = HALF_THICK (AutoRouteParameters.style->Diameter); 03571 CheapPointType lastpoint, nextpoint; 03572 routebox_t *lastpath; 03573 BoxType b; 03574 03575 assert (subnet->style == AutoRouteParameters.style); 03576 /*XXX: because we round up odd thicknesses, there's the possibility that 03577 * a connecting line end-point might be 0.005 mil off the "real" edge. 03578 * don't worry about this because line *thicknesses* are always >= 0.01 mil. */ 03579 03580 /* if we start with a thermal the target was a plane 03581 * or the target was a pin and the source a plane 03582 * in which case this thermal is the whole path 03583 */ 03584 if (path->flags.is_thermal) 03585 { 03586 /* the target was a plane, so we need to find a good spot for the via 03587 * now. It's logical to place it close to the source box which 03588 * is where we're utlimately headed on this path. However, it 03589 * must reside in the plane as well as the via area too. 03590 */ 03591 nextpoint.X = CENTER_X (path->sbox); 03592 nextpoint.Y = CENTER_Y (path->sbox); 03593 if (path->parent.expansion_area->flags.is_via) 03594 { 03595 TargetPoint (&nextpoint, rb_source (path)); 03596 /* nextpoint is the middle of the source terminal now */ 03597 b = clip_box (&path->sbox, &path->parent.expansion_area->sbox); 03598 nextpoint = closest_point_in_box (&nextpoint, &b); 03599 /* now it's in the via and plane near the source */ 03600 } 03601 else /* no via coming, target must have been a pin */ 03602 { 03603 assert (target->type == PIN); 03604 TargetPoint (&nextpoint, target); 03605 } 03606 assert (point_in_box (&path->sbox, nextpoint.X, nextpoint.Y)); 03607 RD_DrawThermal (rd, nextpoint.X, nextpoint.Y, path->group, 03608 path->layer, subnet, is_bad); 03609 } 03610 else 03611 { 03612 /* start from best place of target box */ 03613 lastpoint.X = CENTER_X (target->sbox); 03614 lastpoint.Y = CENTER_Y (target->sbox); 03615 TargetPoint (&lastpoint, target); 03616 if (AutoRouteParameters.last_smooth 03617 && box_in_box (&path->sbox, &target->sbox)) 03618 path = path->parent.expansion_area; 03619 b = path->sbox; 03620 if (path->flags.circular) 03621 b = shrink_box (&b, MIN (b.X2 - b.X1, b.Y2 - b.Y1) / 5); 03622 nextpoint = closest_point_in_box (&lastpoint, &b); 03623 if (AutoRouteParameters.last_smooth) 03624 RD_DrawLine (rd, lastpoint.X, lastpoint.Y, nextpoint.X, nextpoint.Y, 03625 halfwidth, path->group, subnet, is_bad, TRUE); 03626 else 03627 last_x = RD_DrawManhattanLine (rd, &target->sbox, &path->sbox, 03628 lastpoint, nextpoint, halfwidth, 03629 path->group, subnet, is_bad, last_x); 03630 } 03631 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ROUTE_BOXES) 03632 showroutebox (path); 03633 #if defined(ROUTE_VERBOSE) 03634 pcb_printf ("TRACEPOINT start %#mD\n", nextpoint.X, nextpoint.Y); 03635 #endif 03636 #endif 03637 03638 do 03639 { 03640 lastpoint = nextpoint; 03641 lastpath = path; 03642 assert (path->type == EXPANSION_AREA); 03643 path = path->parent.expansion_area; 03644 b = path->sbox; 03645 if (path->flags.circular) 03646 b = shrink_box (&b, MIN (b.X2 - b.X1, b.Y2 - b.Y1) / 5); 03647 assert (b.X1 != b.X2 && b.Y1 != b.Y2); /* need someplace to put line! */ 03648 /* find point on path perimeter closest to last point */ 03649 /* if source terminal, try to hit a good place */ 03650 nextpoint = closest_point_in_box (&lastpoint, &b); 03651 #if 0 03652 /* leave more clearance if this is a smoothing pass */ 03653 if (AutoRouteParameters.is_smoothing && 03654 (nextpoint.X != lastpoint.X || nextpoint.Y != lastpoint.Y)) 03655 add_clearance (&nextpoint, &b); 03656 #endif 03657 if (path->flags.source && path->type != PLANE) 03658 TargetPoint (&nextpoint, path); 03659 assert (point_in_box (&lastpath->box, lastpoint.X, lastpoint.Y)); 03660 assert (point_in_box (&path->box, nextpoint.X, nextpoint.Y)); 03661 #if defined(ROUTE_DEBUG_VERBOSE) 03662 printf ("TRACEPATH: "); 03663 DumpRouteBox (path); 03664 pcb_printf ("TRACEPATH: point %#mD to point %#mD layer %d\n", 03665 lastpoint.X, lastpoint.Y, nextpoint.X, nextpoint.Y, 03666 path->group); 03667 #endif 03668 03669 /* draw orthogonal lines from lastpoint to nextpoint */ 03670 /* knee is placed in lastpath box */ 03671 /* should never cause line to leave union of lastpath/path boxes */ 03672 if (AutoRouteParameters.last_smooth) 03673 RD_DrawLine (rd, lastpoint.X, lastpoint.Y, nextpoint.X, nextpoint.Y, 03674 halfwidth, path->group, subnet, is_bad, TRUE); 03675 else 03676 last_x = RD_DrawManhattanLine (rd, &lastpath->sbox, &path->sbox, 03677 lastpoint, nextpoint, halfwidth, 03678 path->group, subnet, is_bad, last_x); 03679 if (path->flags.is_via) 03680 { /* if via, then add via */ 03681 #ifdef ROUTE_VERBOSE 03682 printf (" (vias)"); 03683 #endif 03684 assert (point_in_box (&path->box, nextpoint.X, nextpoint.Y)); 03685 RD_DrawVia (rd, nextpoint.X, nextpoint.Y, radius, subnet, is_bad); 03686 } 03687 03688 assert (lastpath->flags.is_via || path->group == lastpath->group); 03689 03690 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_ROUTE_BOXES) 03691 showroutebox (path); 03692 #endif /* ROUTE_DEBUG && DEBUG_SHOW_ROUTE_BOXES */ 03693 /* if this is connected to a plane, draw the thermal */ 03694 if (path->flags.is_thermal || path->type == PLANE) 03695 RD_DrawThermal (rd, lastpoint.X, lastpoint.Y, path->group, 03696 path->layer, subnet, is_bad); 03697 /* when one hop from the source, make an extra path in *this* box */ 03698 if (path->type == EXPANSION_AREA 03699 && path->parent.expansion_area->flags.source 03700 && path->parent.expansion_area->type != PLANE) 03701 { 03702 /* find special point on source (if it exists) */ 03703 if (TargetPoint (&lastpoint, path->parent.expansion_area)) 03704 { 03705 lastpoint = closest_point_in_routebox (&lastpoint, path); 03706 b = shrink_routebox (path); 03707 #if 0 03708 if (AutoRouteParameters.is_smoothing) 03709 add_clearance (&lastpoint, &b); 03710 #else 03711 if (AutoRouteParameters.last_smooth) 03712 RD_DrawLine (rd, lastpoint.X, lastpoint.Y, nextpoint.X, 03713 nextpoint.Y, halfwidth, path->group, subnet, 03714 is_bad, TRUE); 03715 else 03716 #endif 03717 last_x = RD_DrawManhattanLine (rd, &b, &b, 03718 nextpoint, lastpoint, 03719 halfwidth, path->group, subnet, 03720 is_bad, last_x); 03721 #if defined(ROUTE_DEBUG_VERBOSE) 03722 printf ("TRACEPATH: "); 03723 DumpRouteBox (path); 03724 pcb_printf 03725 ("TRACEPATH: (to source) point %#mD to point %#mD layer %d\n", 03726 nextpoint.X, nextpoint.Y, lastpoint.X, lastpoint.Y, 03727 path->group); 03728 #endif 03729 03730 nextpoint = lastpoint; 03731 } 03732 } 03733 } 03734 while (!path->flags.source); 03735 /* flush the line queue */ 03736 RD_DrawLine (rd, -1, 0, 0, 0, 0, 0, NULL, false, false); 03737 03738 if (TEST_FLAG (LIVEROUTEFLAG, PCB)) 03739 Draw (); 03740 03741 #ifdef ROUTE_DEBUG 03742 if (ddraw != NULL) 03743 gui->flush_debug_draw (); 03744 #endif 03745 } 03746 03750 static void 03751 CreateSearchEdge (struct routeone_state *s, vetting_t * work, edge_t * parent, 03752 routebox_t * rb, conflict_t conflict, rtree_t * targets, 03753 bool in_plane) 03754 { 03755 routebox_t *target; 03756 BoxType b; 03757 cost_t cost; 03758 assert (__routebox_is_good (rb)); 03759 /* find the cheapest target */ 03760 #if 0 03761 target = 03762 mincost_target_to_point (&parent->cost_point, max_group + 1, targets, 03763 parent->mincost_target); 03764 #else 03765 target = parent->mincost_target; 03766 #endif 03767 b = shrink_routebox (target); 03768 cost = 03769 parent->cost_to_point + AutoRouteParameters.ViaCost + 03770 cost_to_layerless_box (&rb->cost_point, 0, &b); 03771 if (cost < s->best_cost) 03772 { 03773 edge_t *ne; 03774 ne = (edge_t *)malloc (sizeof (*ne)); 03775 memset ((void *) ne, 0, sizeof (*ne)); 03776 assert (ne); 03777 ne->flags.via_search = 1; 03778 ne->flags.in_plane = in_plane; 03779 ne->rb = rb; 03780 if (rb->flags.homeless) 03781 RB_up_count (rb); 03782 ne->work = work; 03783 ne->mincost_target = target; 03784 ne->flags.via_conflict_level = conflict; 03785 ne->cost_to_point = parent->cost_to_point; 03786 ne->cost_point = parent->cost_point; 03787 ne->cost = cost; 03788 heap_insert (s->workheap, ne->cost, ne); 03789 } 03790 else 03791 { 03792 mtsFreeWork (&work); 03793 } 03794 } 03795 03796 static void 03797 add_or_destroy_edge (struct routeone_state *s, edge_t * e) 03798 { 03799 e->cost = edge_cost (e, s->best_cost); 03800 assert (__edge_is_good (e)); 03801 assert (is_layer_group_active[e->rb->group]); 03802 if (e->cost < s->best_cost) 03803 heap_insert (s->workheap, e->cost, e); 03804 else 03805 DestroyEdge (&e); 03806 } 03807 03808 static void 03809 best_path_candidate (struct routeone_state *s, 03810 edge_t * e, routebox_t * best_target) 03811 { 03812 e->cost = edge_cost (e, EXPENSIVE); 03813 if (s->best_path == NULL || e->cost < s->best_cost) 03814 { 03815 #if defined(ROUTE_DEBUG) && defined (ROUTE_VERBOSE) 03816 printf ("New best path seen! cost = %f\n", e->cost); 03817 #endif 03818 /* new best path! */ 03819 if (s->best_path && s->best_path->flags.homeless) 03820 RB_down_count (s->best_path); 03821 s->best_path = e->rb; 03822 s->best_target = best_target; 03823 s->best_cost = e->cost; 03824 assert (s->best_cost >= 0); 03825 /* don't free this when we destroy edge! */ 03826 if (s->best_path->flags.homeless) 03827 RB_up_count (s->best_path); 03828 } 03829 } 03830 03831 03835 struct routeone_via_site_state 03836 { 03837 vector_t *free_space_vec; 03838 vector_t *lo_conflict_space_vec; 03839 vector_t *hi_conflict_space_vec; 03840 }; 03841 03842 void 03843 add_via_sites (struct routeone_state *s, 03844 struct routeone_via_site_state *vss, 03845 mtspace_t * mtspace, routebox_t * within, 03846 conflict_t within_conflict_level, edge_t * parent_edge, 03847 rtree_t * targets, Coord shrink, bool in_plane) 03848 { 03849 Coord radius, keepaway; 03850 vetting_t *work; 03851 BoxType region = shrink_routebox (within); 03852 shrink_box (®ion, shrink); 03853 03854 radius = HALF_THICK (AutoRouteParameters.style->Diameter); 03855 keepaway = AutoRouteParameters.style->Keepaway; 03856 assert (AutoRouteParameters.use_vias); 03857 /* XXX: need to clip 'within' to shrunk_pcb_bounds, because when 03858 XXX: routing with conflicts may poke over edge. */ 03859 03860 /* ask for a via box near our cost_point first */ 03861 work = mtspace_query_rect (mtspace, ®ion, radius, keepaway, 03862 NULL, vss->free_space_vec, 03863 vss->lo_conflict_space_vec, 03864 vss->hi_conflict_space_vec, 03865 AutoRouteParameters.is_odd, 03866 AutoRouteParameters.with_conflicts, 03867 &parent_edge->cost_point); 03868 if (!work) 03869 return; 03870 CreateSearchEdge (s, work, parent_edge, within, within_conflict_level, 03871 targets, in_plane); 03872 } 03873 03874 void 03875 do_via_search (edge_t * search, struct routeone_state *s, 03876 struct routeone_via_site_state *vss, mtspace_t * mtspace, 03877 rtree_t * targets) 03878 { 03879 int i, j, count = 0; 03880 Coord radius, keepaway; 03881 vetting_t *work; 03882 routebox_t *within; 03883 conflict_t within_conflict_level; 03884 03885 radius = HALF_THICK (AutoRouteParameters.style->Diameter); 03886 keepaway = AutoRouteParameters.style->Keepaway; 03887 work = mtspace_query_rect (mtspace, NULL, 0, 0, 03888 search->work, vss->free_space_vec, 03889 vss->lo_conflict_space_vec, 03890 vss->hi_conflict_space_vec, 03891 AutoRouteParameters.is_odd, 03892 AutoRouteParameters.with_conflicts, NULL); 03893 within = search->rb; 03894 within_conflict_level = search->flags.via_conflict_level; 03895 for (i = 0; i < 3; i++) 03896 { 03897 vector_t *v = 03898 (i == NO_CONFLICT ? vss->free_space_vec : 03899 i == LO_CONFLICT ? vss->lo_conflict_space_vec : 03900 i == HI_CONFLICT ? vss->hi_conflict_space_vec : NULL); 03901 assert (v); 03902 while (!vector_is_empty (v)) 03903 { 03904 BoxType cliparea; 03905 BoxType *area = (BoxType *)vector_remove_last (v); 03906 if (!(i == NO_CONFLICT || AutoRouteParameters.with_conflicts)) 03907 { 03908 free (area); 03909 continue; 03910 } 03911 /* answers are bloated by radius + keepaway */ 03912 cliparea = shrink_box (area, radius + keepaway); 03913 close_box (&cliparea); 03914 free (area); 03915 assert (box_is_good (&cliparea)); 03916 count++; 03917 for (j = 0; j < max_group; j++) 03918 { 03919 edge_t *ne; 03920 if (j == within->group || !is_layer_group_active[j]) 03921 continue; 03922 ne = CreateViaEdge (&cliparea, j, within, search, 03923 within_conflict_level, (conflict_t)i, targets); 03924 add_or_destroy_edge (s, ne); 03925 } 03926 } 03927 } 03928 /* prevent freeing of work when this edge is destroyed */ 03929 search->flags.via_search = 0; 03930 if (!work) 03931 return; 03932 CreateSearchEdge (s, work, search, within, within_conflict_level, targets, 03933 search->flags.in_plane); 03934 assert (vector_is_empty (vss->free_space_vec)); 03935 assert (vector_is_empty (vss->lo_conflict_space_vec)); 03936 assert (vector_is_empty (vss->hi_conflict_space_vec)); 03937 } 03938 03939 /* vector of expansion areas to be eventually removed from r-tree 03940 * this is a global for troubleshooting 03941 */ 03942 vector_t *area_vec; 03943 03944 /* some routines for use in gdb while debugging */ 03945 #if defined(ROUTE_DEBUG) 03946 static void 03947 list_conflicts (routebox_t * rb) 03948 { 03949 int i, n; 03950 if (!rb->conflicts_with) 03951 return; 03952 n = vector_size (rb->conflicts_with); 03953 for (i = 0; i < n; i++) 03954 printf ("%p, ", vector_element (rb->conflicts_with, i)); 03955 } 03956 03957 static void 03958 show_area_vec (int lay) 03959 { 03960 int n, save; 03961 03962 if (!area_vec) 03963 return; 03964 save = showboxen; 03965 showboxen = lay; 03966 for (n = 0; n < vector_size (area_vec); n++) 03967 { 03968 routebox_t *rb = (routebox_t *) vector_element (area_vec, n); 03969 showroutebox (rb); 03970 } 03971 showboxen = save; 03972 } 03973 03974 static bool 03975 net_id (routebox_t * rb, long int id) 03976 { 03977 routebox_t *p; 03978 LIST_LOOP (rb, same_net, p); 03979 if (p->flags.source && p->parent.pad->ID == id) 03980 return true; 03981 END_LOOP; 03982 return false; 03983 } 03984 03985 static void 03986 trace_parents (routebox_t * rb) 03987 { 03988 while (rb && rb->type == EXPANSION_AREA) 03989 { 03990 printf (" %p ->", rb); 03991 rb = rb->parent.expansion_area; 03992 } 03993 if (rb) 03994 printf (" %p is source\n", rb); 03995 else 03996 printf ("NULL!\n"); 03997 } 03998 03999 static void 04000 show_one (routebox_t * rb) 04001 { 04002 int save = showboxen; 04003 showboxen = -1; 04004 showroutebox (rb); 04005 showboxen = save; 04006 } 04007 04008 static void 04009 show_path (routebox_t * rb) 04010 { 04011 while (rb && rb->type == EXPANSION_AREA) 04012 { 04013 show_one (rb); 04014 rb = rb->parent.expansion_area; 04015 } 04016 show_one (rb); 04017 } 04018 04019 static void 04020 show_sources (routebox_t * rb) 04021 { 04022 routebox_t *p; 04023 if (!rb->flags.source && !rb->flags.target) 04024 { 04025 printf ("start with a source or target please\n"); 04026 return; 04027 } 04028 LIST_LOOP (rb, same_net, p); 04029 if (p->flags.source) 04030 show_one (p); 04031 END_LOOP; 04032 } 04033 04034 #endif 04035 04036 static int 04037 __conflict_source (const BoxType * box, void *cl) 04038 { 04039 routebox_t *rb = (routebox_t *) box; 04040 if (rb->flags.touched || rb->flags.fixed) 04041 return 0; 04042 else 04043 { 04044 routebox_t *dis = (routebox_t *) cl; 04045 path_conflicts (dis, rb, false); 04046 touch_conflicts (dis->conflicts_with, 1); 04047 } 04048 return 1; 04049 } 04050 04051 static void 04052 source_conflicts (rtree_t * tree, routebox_t * rb) 04053 { 04054 if (!AutoRouteParameters.with_conflicts) 04055 return; 04056 r_search (tree, &rb->sbox, NULL, __conflict_source, rb); 04057 touch_conflicts (NULL, 1); 04058 } 04059 04060 struct routeone_status 04061 { 04062 bool found_route; 04063 int route_had_conflicts; 04064 cost_t best_route_cost; 04065 bool net_completely_routed; 04066 }; 04067 04068 04069 static struct routeone_status 04070 RouteOne (routedata_t * rd, routebox_t * from, routebox_t * to, int max_edges) 04071 { 04072 struct routeone_status result; 04073 routebox_t *p; 04074 int seen, i; 04075 const BoxType **target_list; 04076 int num_targets; 04077 rtree_t *targets; 04078 /* vector of source edges for filtering */ 04079 vector_t *source_vec; 04080 /* working vector */ 04081 vector_t *edge_vec; 04082 04083 struct routeone_state s; 04084 struct routeone_via_site_state vss; 04085 04086 assert (rd && from); 04087 result.route_had_conflicts = 0; 04088 /* no targets on to/from net need keepaway areas */ 04089 LIST_LOOP (from, same_net, p); 04090 p->flags.nobloat = 1; 04091 END_LOOP; 04092 /* set 'source' flags */ 04093 LIST_LOOP (from, same_subnet, p); 04094 if (!p->flags.nonstraight) 04095 p->flags.source = 1; 04096 END_LOOP; 04097 04098 /* count up the targets */ 04099 num_targets = 0; 04100 seen = 0; 04101 /* remove source/target flags from non-straight obstacles, because they 04102 * don't fill their bounding boxes and so connecting to them 04103 * after we've routed is problematic. Better solution? */ 04104 if (to) 04105 { /* if we're routing to a specific target */ 04106 if (!to->flags.source) 04107 { /* not already connected */ 04108 /* check that 'to' and 'from' are on the same net */ 04109 seen = 0; 04110 #ifndef NDEBUG 04111 LIST_LOOP (from, same_net, p); 04112 if (p == to) 04113 seen = 1; 04114 END_LOOP; 04115 #endif 04116 assert (seen); /* otherwise from and to are on different nets! */ 04117 /* set target flags only on 'to's subnet */ 04118 LIST_LOOP (to, same_subnet, p); 04119 if (!p->flags.nonstraight && is_layer_group_active[p->group]) 04120 { 04121 p->flags.target = 1; 04122 num_targets++; 04123 } 04124 END_LOOP; 04125 } 04126 } 04127 else 04128 { 04129 /* all nodes on the net but not connected to from are targets */ 04130 LIST_LOOP (from, same_net, p); 04131 if (!p->flags.source && is_layer_group_active[p->group] 04132 && !p->flags.nonstraight) 04133 { 04134 p->flags.target = 1; 04135 num_targets++; 04136 } 04137 END_LOOP; 04138 } 04139 04140 /* if no targets, then net is done! reset flags and return. */ 04141 if (num_targets == 0) 04142 { 04143 LIST_LOOP (from, same_net, p); 04144 p->flags.source = p->flags.target = p->flags.nobloat = 0; 04145 END_LOOP; 04146 result.found_route = false; 04147 result.net_completely_routed = true; 04148 result.best_route_cost = 0; 04149 result.route_had_conflicts = 0; 04150 04151 return result; 04152 } 04153 result.net_completely_routed = false; 04154 04155 /* okay, there's stuff to route */ 04156 assert (!from->flags.target); 04157 assert (num_targets > 0); 04158 /* create list of target pointers and from that a r-tree of targets */ 04159 target_list = (const BoxType **)malloc (num_targets * sizeof (*target_list)); 04160 i = 0; 04161 LIST_LOOP (from, same_net, p); 04162 if (p->flags.target) 04163 { 04164 target_list[i++] = &p->box; 04165 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_TARGETS) 04166 showroutebox (p); 04167 #endif 04168 } 04169 END_LOOP; 04170 targets = r_create_tree ((const BoxType **)target_list, i, 0); 04171 assert (i <= num_targets); 04172 free (target_list); 04173 04174 source_vec = vector_create (); 04175 /* touch the source subnet to prepare check for conflictors */ 04176 LIST_LOOP (from, same_subnet, p); 04177 p->flags.touched = 1; 04178 END_LOOP; 04179 LIST_LOOP (from, same_subnet, p); 04180 { 04181 /* we need the test for 'source' because this box may be nonstraight */ 04182 if (p->flags.source && is_layer_group_active[p->group]) 04183 { 04184 CheapPointType cp; 04185 edge_t *e; 04186 BoxType b = shrink_routebox (p); 04187 04188 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_SOURCES) 04189 showroutebox (p); 04190 #endif 04191 /* may expand in all directions from source; center edge cost point. */ 04192 /* note that planes shouldn't really expand, but we need an edge */ 04193 04194 cp.X = CENTER_X (b); 04195 cp.Y = CENTER_Y (b); 04196 e = CreateEdge (p, cp.X, cp.Y, 0, NULL, ALL, targets); 04197 cp = closest_point_in_box (&cp, &e->mincost_target->sbox); 04198 cp = closest_point_in_box (&cp, &b); 04199 e->cost_point = cp; 04200 p->cost_point = cp; 04201 source_conflicts (rd->layergrouptree[p->group], p); 04202 vector_append (source_vec, e); 04203 } 04204 } 04205 END_LOOP; 04206 LIST_LOOP (from, same_subnet, p); 04207 p->flags.touched = 0; 04208 END_LOOP; 04209 /* break source edges; some edges may be too near obstacles to be able 04210 * to exit from. */ 04211 04212 /* okay, main expansion-search routing loop. */ 04213 /* set up the initial activity heap */ 04214 s.workheap = heap_create (); 04215 assert (s.workheap); 04216 while (!vector_is_empty (source_vec)) 04217 { 04218 edge_t *e = (edge_t *)vector_remove_last (source_vec); 04219 assert (is_layer_group_active[e->rb->group]); 04220 e->cost = edge_cost (e, EXPENSIVE); 04221 heap_insert (s.workheap, e->cost, e); 04222 } 04223 vector_destroy (&source_vec); 04224 /* okay, process items from heap until it is empty! */ 04225 s.best_path = NULL; 04226 s.best_cost = EXPENSIVE; 04227 area_vec = vector_create (); 04228 edge_vec = vector_create (); 04229 vss.free_space_vec = vector_create (); 04230 vss.lo_conflict_space_vec = vector_create (); 04231 vss.hi_conflict_space_vec = vector_create (); 04232 while (!heap_is_empty (s.workheap)) 04233 { 04234 edge_t *e = (edge_t *)heap_remove_smallest (s.workheap); 04235 #ifdef ROUTE_DEBUG 04236 if (aabort) 04237 goto dontexpand; 04238 #endif 04239 /* don't bother expanding this edge if the minimum possible edge cost 04240 * is already larger than the best edge cost we've found. */ 04241 if (s.best_path && e->cost >= s.best_cost) 04242 { 04243 heap_free (s.workheap, KillEdge); 04244 goto dontexpand; /* skip this edge */ 04245 } 04246 /* surprisingly it helps to give up and not try too hard to find 04247 * a route! This is not only faster, but results in better routing. 04248 * who would have guessed? 04249 */ 04250 if (seen++ > max_edges) 04251 goto dontexpand; 04252 assert (__edge_is_good (e)); 04253 /* mark or unmark conflictors as needed */ 04254 touch_conflicts (e->rb->conflicts_with, 1); 04255 if (e->flags.via_search) 04256 { 04257 do_via_search (e, &s, &vss, rd->mtspace, targets); 04258 goto dontexpand; 04259 } 04260 /* we should never add edges on inactive layer groups to the heap. */ 04261 assert (is_layer_group_active[e->rb->group]); 04262 #if defined(ROUTE_DEBUG) && defined(DEBUG_SHOW_EXPANSION_BOXES) 04263 //showedge (e); 04264 #endif 04265 if (e->rb->flags.is_thermal) 04266 { 04267 best_path_candidate (&s, e, e->mincost_target); 04268 goto dontexpand; 04269 } 04270 /* for a plane, look for quick connections with thermals or vias */ 04271 if (e->rb->type == PLANE) 04272 { 04273 routebox_t *pin = FindThermable (targets, e->rb); 04274 if (pin) 04275 { 04276 BoxType b = shrink_routebox (pin); 04277 edge_t *ne; 04278 routebox_t *nrb; 04279 assert (pin->flags.target); 04280 nrb = CreateExpansionArea (&b, e->rb->group, e->rb, true, e); 04281 nrb->flags.is_thermal = 1; 04282 /* moving through the plane is free */ 04283 e->cost_point.X = b.X1; 04284 e->cost_point.Y = b.Y1; 04285 ne = CreateEdge2 (nrb, e->expand_dir, e, NULL, pin); 04286 best_path_candidate (&s, ne, pin); 04287 DestroyEdge (&ne); 04288 } 04289 else 04290 { 04291 /* add in possible via sites in plane */ 04292 if (AutoRouteParameters.use_vias && 04293 e->cost + AutoRouteParameters.ViaCost < s.best_cost) 04294 { 04295 /* we need a giant thermal */ 04296 routebox_t *nrb = 04297 CreateExpansionArea (&e->rb->sbox, e->rb->group, e->rb, 04298 true, e); 04299 edge_t *ne = CreateEdge2 (nrb, e->expand_dir, e, NULL, 04300 e->mincost_target); 04301 nrb->flags.is_thermal = 1; 04302 add_via_sites (&s, &vss, rd->mtspace, nrb, NO_CONFLICT, ne, 04303 targets, e->rb->style->Diameter, true); 04304 } 04305 } 04306 goto dontexpand; /* planes only connect via thermals */ 04307 } 04308 if (e->flags.is_via) 04309 { /* special case via */ 04310 routebox_t *intersecting; 04311 assert (AutoRouteParameters.use_vias); 04312 assert (e->expand_dir == ALL); 04313 assert (vector_is_empty (edge_vec)); 04314 /* if there is already something here on this layer (like an 04315 * EXPANSION_AREA), then we don't want to expand from here 04316 * at least not inside the expansion area. A PLANE on the 04317 * other hand may be a target, or not. 04318 */ 04319 intersecting = 04320 FindOneInBox (rd->layergrouptree[e->rb->group], e->rb); 04321 04322 if (intersecting && intersecting->flags.target 04323 && intersecting->type == PLANE) 04324 { 04325 /* we have hit a plane */ 04326 edge_t *ne; 04327 routebox_t *nrb; 04328 BoxType b = shrink_routebox (e->rb); 04329 /* limit via region to that inside the plane */ 04330 clip_box (&b, &intersecting->sbox); 04331 nrb = CreateExpansionArea (&b, e->rb->group, e->rb, true, e); 04332 nrb->flags.is_thermal = 1; 04333 ne = CreateEdge2 (nrb, e->expand_dir, e, NULL, intersecting); 04334 best_path_candidate (&s, ne, intersecting); 04335 DestroyEdge (&ne); 04336 goto dontexpand; 04337 } 04338 else if (intersecting == NULL) 04339 { 04340 /* this via candidate is in an open area; add it to r-tree as 04341 * an expansion area */ 04342 assert (e->rb->type == EXPANSION_AREA && e->rb->flags.is_via); 04343 /*assert (!r_search (rd->layergrouptree[e->rb->group], 04344 &e->rb->box, NULL, no_planes,0)); 04345 */ 04346 r_insert_entry (rd->layergrouptree[e->rb->group], &e->rb->box, 04347 1); 04348 e->rb->flags.homeless = 0; /* not homeless any more */ 04349 /* add to vector of all expansion areas in r-tree */ 04350 vector_append (area_vec, e->rb); 04351 /* mark reset refcount to 0, since this is not homeless any more. */ 04352 e->rb->refcount = 0; 04353 /* go ahead and expand this edge! */ 04354 } 04355 else if (1) 04356 goto dontexpand; 04357 else if (0) 04358 { /* XXX: disabling this causes no via 04359 collisions. */ 04360 BoxType a = bloat_routebox (intersecting), b; 04361 edge_t *ne; 04362 int i, j; 04363 /* something intersects this via candidate. split via candidate 04364 * into pieces and add these pieces to the workheap. */ 04365 for (i = 0; i < 3; i++) 04366 { 04367 for (j = 0; j < 3; j++) 04368 { 04369 b = shrink_routebox (e->rb); 04370 switch (i) 04371 { 04372 case 0: 04373 b.X2 = MIN (b.X2, a.X1); 04374 break; /* left */ 04375 case 1: 04376 b.X1 = MAX (b.X1, a.X1); 04377 b.X2 = MIN (b.X2, a.X2); 04378 break; /*c */ 04379 case 2: 04380 b.X1 = MAX (b.X1, a.X2); 04381 break; /* right */ 04382 default: 04383 assert (0); 04384 } 04385 switch (j) 04386 { 04387 case 0: 04388 b.Y2 = MIN (b.Y2, a.Y1); 04389 break; /* top */ 04390 case 1: 04391 b.Y1 = MAX (b.Y1, a.Y1); 04392 b.Y2 = MIN (b.Y2, a.Y2); 04393 break; /*c */ 04394 case 2: 04395 b.Y1 = MAX (b.Y1, a.Y2); 04396 break; /* bottom */ 04397 default: 04398 assert (0); 04399 } 04400 /* skip if this box is not valid */ 04401 if (!(b.X1 < b.X2 && b.Y1 < b.Y2)) 04402 continue; 04403 if (i == 1 && j == 1) 04404 { 04405 /* this bit of the via space is obstructed. */ 04406 if (intersecting->type == EXPANSION_AREA 04407 || intersecting->flags.fixed) 04408 continue; /* skip this bit, it's already been done. */ 04409 /* create an edge with conflicts, if enabled */ 04410 if (!AutoRouteParameters.with_conflicts) 04411 continue; 04412 ne = CreateEdgeWithConflicts (&b, intersecting, e, 1 04413 /*cost penalty to box */ 04414 , targets); 04415 add_or_destroy_edge (&s, ne); 04416 } 04417 else 04418 { 04419 /* if this is not the intersecting piece, create a new 04420 * (hopefully unobstructed) via edge and add it back to the 04421 * workheap. */ 04422 ne = 04423 CreateViaEdge (&b, e->rb->group, 04424 e->rb->parent.expansion_area, e, 04425 e->flags.via_conflict_level, 04426 NO_CONFLICT 04427 /* value here doesn't matter */ 04428 , targets); 04429 add_or_destroy_edge (&s, ne); 04430 } 04431 } 04432 } 04433 goto dontexpand; 04434 } 04435 /* between the time these edges are inserted and the 04436 * time they are processed, new expansion boxes (which 04437 * conflict with these edges) may be added to the graph! 04438 * w.o vias this isn't a problem because the broken box 04439 * is not homeless. */ 04440 } 04441 if (1) 04442 { 04443 routebox_t *nrb; 04444 struct E_result *ans; 04445 BoxType b; 04446 vector_t *broken; 04447 if (e->flags.is_interior) 04448 { 04449 assert (AutoRouteParameters.with_conflicts); /* no interior edges unless 04450 routing with conflicts! */ 04451 assert (e->rb->conflicts_with); 04452 b = e->rb->sbox; 04453 switch (e->rb->came_from) 04454 { 04455 case NORTH: 04456 b.Y2 = b.Y1 + 1; 04457 b.X1 = CENTER_X (b); 04458 b.X2 = b.X1 + 1; 04459 break; 04460 case EAST: 04461 b.X1 = b.X2 - 1; 04462 b.Y1 = CENTER_Y (b); 04463 b.Y2 = b.Y1 + 1; 04464 break; 04465 case SOUTH: 04466 b.Y1 = b.Y2 - 1; 04467 b.X1 = CENTER_X (b); 04468 b.X2 = b.X1 + 1; 04469 break; 04470 case WEST: 04471 b.X2 = b.X1 + 1; 04472 b.Y1 = CENTER_Y (b); 04473 b.Y2 = b.Y1 + 1; 04474 break; 04475 default: 04476 assert (0); 04477 } 04478 } 04479 /* sources may not expand to their own edges because of 04480 * adjacent blockers. 04481 */ 04482 else if (e->rb->flags.source) 04483 b = box_center (&e->rb->sbox); 04484 else 04485 b = e->rb->sbox; 04486 ans = Expand (rd->layergrouptree[e->rb->group], e, &b); 04487 if (!box_intersect (&ans->inflated, &ans->orig)) 04488 goto dontexpand; 04489 #if 0 04490 /* skip if it didn't actually expand */ 04491 if (ans->inflated.X1 >= e->rb->sbox.X1 && 04492 ans->inflated.X2 <= e->rb->sbox.X2 && 04493 ans->inflated.Y1 >= e->rb->sbox.Y1 && 04494 ans->inflated.Y2 <= e->rb->sbox.Y2) 04495 goto dontexpand; 04496 #endif 04497 04498 if (!box_is_good (&ans->inflated)) 04499 goto dontexpand; 04500 nrb = CreateExpansionArea (&ans->inflated, e->rb->group, e->rb, 04501 true, e); 04502 r_insert_entry (rd->layergrouptree[nrb->group], &nrb->box, 1); 04503 vector_append (area_vec, nrb); 04504 nrb->flags.homeless = 0; /* not homeless any more */ 04505 broken = 04506 BreakManyEdges (&s, targets, rd->layergrouptree[nrb->group], 04507 area_vec, ans, nrb, e); 04508 while (!vector_is_empty (broken)) 04509 { 04510 edge_t *ne = (edge_t *)vector_remove_last (broken); 04511 add_or_destroy_edge (&s, ne); 04512 } 04513 vector_destroy (&broken); 04514 04515 /* add in possible via sites in nrb */ 04516 if (AutoRouteParameters.use_vias && !e->rb->flags.is_via && 04517 e->cost + AutoRouteParameters.ViaCost < s.best_cost) 04518 add_via_sites (&s, &vss, 04519 rd->mtspace, nrb, NO_CONFLICT, e, targets, 0, 04520 false); 04521 goto dontexpand; 04522 } 04523 dontexpand: 04524 DestroyEdge (&e); 04525 } 04526 touch_conflicts (NULL, 1); 04527 heap_destroy (&s.workheap); 04528 r_destroy_tree (&targets); 04529 assert (vector_is_empty (edge_vec)); 04530 vector_destroy (&edge_vec); 04531 04532 /* we should have a path in best_path now */ 04533 if (s.best_path) 04534 { 04535 routebox_t *rb; 04536 #ifdef ROUTE_VERBOSE 04537 printf ("%d:%d RC %.0f", ro++, seen, s.best_cost); 04538 #endif 04539 result.found_route = true; 04540 result.best_route_cost = s.best_cost; 04541 /* determine if the best path had conflicts */ 04542 result.route_had_conflicts = 0; 04543 if (AutoRouteParameters.with_conflicts && s.best_path->conflicts_with) 04544 { 04545 while (!vector_is_empty (s.best_path->conflicts_with)) 04546 { 04547 rb = (routebox_t *)vector_remove_last (s.best_path->conflicts_with); 04548 rb->flags.is_bad = 1; 04549 result.route_had_conflicts++; 04550 } 04551 } 04552 #ifdef ROUTE_VERBOSE 04553 if (result.route_had_conflicts) 04554 printf (" (%d conflicts)", result.route_had_conflicts); 04555 #endif 04556 if (result.route_had_conflicts < AutoRouteParameters.hi_conflict) 04557 { 04558 /* back-trace the path and add lines/vias to r-tree */ 04559 TracePath (rd, s.best_path, s.best_target, from, 04560 result.route_had_conflicts); 04561 MergeNets (from, s.best_target, SUBNET); 04562 } 04563 else 04564 { 04565 #ifdef ROUTE_VERBOSE 04566 printf (" (too many in fact)"); 04567 #endif 04568 result.found_route = false; 04569 } 04570 #ifdef ROUTE_VERBOSE 04571 printf ("\n"); 04572 #endif 04573 } 04574 else 04575 { 04576 #ifdef ROUTE_VERBOSE 04577 printf ("%d:%d NO PATH FOUND.\n", ro++, seen); 04578 #endif 04579 result.best_route_cost = s.best_cost; 04580 result.found_route = false; 04581 } 04582 /* now remove all expansion areas from the r-tree. */ 04583 while (!vector_is_empty (area_vec)) 04584 { 04585 routebox_t *rb = (routebox_t *)vector_remove_last (area_vec); 04586 assert (!rb->flags.homeless); 04587 if (rb->conflicts_with 04588 && rb->parent.expansion_area->conflicts_with != rb->conflicts_with) 04589 vector_destroy (&rb->conflicts_with); 04590 r_delete_entry (rd->layergrouptree[rb->group], &rb->box); 04591 } 04592 vector_destroy (&area_vec); 04593 /* clean up; remove all 'source', 'target', and 'nobloat' flags */ 04594 LIST_LOOP (from, same_net, p); 04595 if (p->flags.source && p->conflicts_with) 04596 vector_destroy (&p->conflicts_with); 04597 p->flags.touched = p->flags.source = p->flags.target = p->flags.nobloat = 0; 04598 END_LOOP; 04599 04600 vector_destroy (&vss.free_space_vec); 04601 vector_destroy (&vss.lo_conflict_space_vec); 04602 vector_destroy (&vss.hi_conflict_space_vec); 04603 04604 return result; 04605 } 04606 04607 static void 04608 InitAutoRouteParameters (int pass, 04609 RouteStyleType * style, 04610 bool with_conflicts, bool is_smoothing, 04611 bool lastpass) 04612 { 04613 int i; 04614 /* routing style */ 04615 AutoRouteParameters.style = style; 04616 AutoRouteParameters.bloat = style->Keepaway + HALF_THICK (style->Thick); 04617 /* costs */ 04618 AutoRouteParameters.ViaCost = 04619 INCH_TO_COORD (3.5) + style->Diameter * (is_smoothing ? 80 : 30); 04620 AutoRouteParameters.LastConflictPenalty = 04621 (400 * pass / passes + 2) / (pass + 1); 04622 AutoRouteParameters.ConflictPenalty = 04623 4 * AutoRouteParameters.LastConflictPenalty; 04624 AutoRouteParameters.JogPenalty = 1000 * (is_smoothing ? 20 : 4); 04625 AutoRouteParameters.CongestionPenalty = 1e6; 04626 AutoRouteParameters.MinPenalty = EXPENSIVE; 04627 for (i = 0; i < max_group; i++) 04628 { 04629 if (is_layer_group_active[i]) 04630 { 04631 AutoRouteParameters.MinPenalty = MIN (x_cost[i], 04632 AutoRouteParameters. 04633 MinPenalty); 04634 AutoRouteParameters.MinPenalty = 04635 MIN (y_cost[i], AutoRouteParameters.MinPenalty); 04636 } 04637 } 04638 AutoRouteParameters.NewLayerPenalty = is_smoothing ? 04639 0.5 * EXPENSIVE : 10 * AutoRouteParameters.ViaCost; 04640 /* other */ 04641 AutoRouteParameters.hi_conflict = MAX (8 * (passes - pass + 1), 6); 04642 AutoRouteParameters.is_odd = (pass & 1); 04643 AutoRouteParameters.with_conflicts = with_conflicts; 04644 AutoRouteParameters.is_smoothing = is_smoothing; 04645 AutoRouteParameters.rip_always = is_smoothing; 04646 AutoRouteParameters.last_smooth = 0; //lastpass; 04647 AutoRouteParameters.pass = pass + 1; 04648 } 04649 04650 #ifndef NDEBUG 04651 int 04652 bad_boy (const BoxType * b, void *cl) 04653 { 04654 routebox_t *box = (routebox_t *) b; 04655 if (box->type == EXPANSION_AREA) 04656 return 1; 04657 return 0; 04658 } 04659 04660 bool 04661 no_expansion_boxes (routedata_t * rd) 04662 { 04663 int i; 04664 BoxType big; 04665 big.X1 = 0; 04666 big.X2 = MAX_COORD; 04667 big.Y1 = 0; 04668 big.Y2 = MAX_COORD; 04669 for (i = 0; i < max_group; i++) 04670 { 04671 if (r_search (rd->layergrouptree[i], &big, NULL, bad_boy, NULL)) 04672 return false; 04673 } 04674 return true; 04675 } 04676 #endif 04677 04678 static void 04679 ripout_livedraw_obj (routebox_t *rb) 04680 { 04681 if (rb->type == LINE && rb->livedraw_obj.line) 04682 { 04683 LayerType *layer = LAYER_PTR (PCB->LayerGroups.Entries[rb->group][0]); 04684 EraseLine (rb->livedraw_obj.line); 04685 DestroyObject (PCB->Data, LINE_TYPE, layer, rb->livedraw_obj.line, NULL); 04686 rb->livedraw_obj.line = NULL; 04687 } 04688 if (rb->type == VIA && rb->livedraw_obj.via) 04689 { 04690 EraseVia (rb->livedraw_obj.via); 04691 DestroyObject (PCB->Data, VIA_TYPE, rb->livedraw_obj.via, NULL, NULL); 04692 rb->livedraw_obj.via = NULL; 04693 } 04694 } 04695 04696 static int 04697 ripout_livedraw_obj_cb (const BoxType * b, void *cl) 04698 { 04699 routebox_t *box = (routebox_t *) b; 04700 ripout_livedraw_obj (box); 04701 return 0; 04702 } 04703 04704 struct routeall_status 04705 { 04706 /* --- for completion rate statistics ---- */ 04707 int total_subnets; 04708 /* total subnets routed without conflicts */ 04709 int routed_subnets; 04710 /* total subnets routed with conflicts */ 04711 int conflict_subnets; 04712 /* net failted entirely */ 04713 int failed; 04714 /* net was ripped */ 04715 int ripped; 04716 int total_nets_routed; 04717 }; 04718 04719 static double 04720 calculate_progress (double this_heap_item, double this_heap_size, 04721 struct routeall_status *ras) 04722 { 04723 double total_passes = passes + smoothes + 1; /* + 1 is the refinement pass */ 04724 double this_pass = AutoRouteParameters.pass - 1; /* Number passes from zero */ 04725 double heap_fraction = (double)(ras->routed_subnets + ras->conflict_subnets + ras->failed) / 04726 (double)ras->total_subnets; 04727 double pass_fraction = (this_heap_item + heap_fraction ) / this_heap_size; 04728 double process_fraction = (this_pass + pass_fraction) / total_passes; 04729 04730 return process_fraction; 04731 } 04732 04733 struct routeall_status 04734 RouteAll (routedata_t * rd) 04735 { 04736 struct routeall_status ras; 04737 struct routeone_status ros; 04738 bool rip; 04739 int request_cancel; 04740 #ifdef NET_HEAP 04741 heap_t *net_heap; 04742 #endif 04743 heap_t *this_pass, *next_pass, *tmp; 04744 routebox_t *net, *p, *pp; 04745 cost_t total_net_cost, last_cost = 0, this_cost = 0; 04746 int i; 04747 int this_heap_size; 04748 int this_heap_item; 04749 04750 /* initialize heap for first pass; 04751 * do smallest area first; that makes 04752 * the subsequent costs more representative */ 04753 this_pass = heap_create (); 04754 next_pass = heap_create (); 04755 #ifdef NET_HEAP 04756 net_heap = heap_create (); 04757 #endif 04758 LIST_LOOP (rd->first_net, different_net, net); 04759 { 04760 double area; 04761 BoxType bb = shrink_routebox (net); 04762 LIST_LOOP (net, same_net, p); 04763 { 04764 MAKEMIN (bb.X1, p->sbox.X1); 04765 MAKEMIN (bb.Y1, p->sbox.Y1); 04766 MAKEMAX (bb.X2, p->sbox.X2); 04767 MAKEMAX (bb.Y2, p->sbox.Y2); 04768 } 04769 END_LOOP; 04770 area = (double) (bb.X2 - bb.X1) * (bb.Y2 - bb.Y1); 04771 heap_insert (this_pass, area, net); 04772 } 04773 END_LOOP; 04774 04775 ras.total_nets_routed = 0; 04776 /* refinement/finishing passes */ 04777 for (i = 0; i <= passes + smoothes; i++) 04778 { 04779 #ifdef ROUTE_VERBOSE 04780 if (i > 0 && i <= passes) 04781 printf ("--------- STARTING REFINEMENT PASS %d ------------\n", i); 04782 else if (i > passes) 04783 printf ("--------- STARTING SMOOTHING PASS %d -------------\n", 04784 i - passes); 04785 #endif 04786 ras.total_subnets = ras.routed_subnets = ras.conflict_subnets = 04787 ras.failed = ras.ripped = 0; 04788 assert (heap_is_empty (next_pass)); 04789 04790 this_heap_size = heap_size (this_pass); 04791 for (this_heap_item = 0; !heap_is_empty (this_pass); this_heap_item++) 04792 { 04793 #ifdef ROUTE_DEBUG 04794 if (aabort) 04795 break; 04796 #endif 04797 net = (routebox_t *) heap_remove_smallest (this_pass); 04798 InitAutoRouteParameters (i, net->style, i < passes, i > passes, 04799 i == passes + smoothes); 04800 if (i > 0) 04801 { 04802 /* rip up all unfixed traces in this net ? */ 04803 if (AutoRouteParameters.rip_always) 04804 rip = true; 04805 else 04806 { 04807 rip = false; 04808 LIST_LOOP (net, same_net, p); 04809 if (p->flags.is_bad) 04810 { 04811 rip = true; 04812 break; 04813 } 04814 END_LOOP; 04815 } 04816 04817 LIST_LOOP (net, same_net, p); 04818 p->flags.is_bad = 0; 04819 if (!p->flags.fixed) 04820 { 04821 #ifndef NDEBUG 04822 bool del; 04823 #endif 04824 assert (!p->flags.homeless); 04825 if (rip) 04826 { 04827 RemoveFromNet (p, NET); 04828 RemoveFromNet (p, SUBNET); 04829 } 04830 if (AutoRouteParameters.use_vias && p->type != VIA_SHADOW 04831 && p->type != PLANE) 04832 { 04833 mtspace_remove (rd->mtspace, &p->box, 04834 p->flags.is_odd ? ODD : EVEN, 04835 p->style->Keepaway); 04836 if (!rip) 04837 mtspace_add (rd->mtspace, &p->box, 04838 p->flags.is_odd ? EVEN : ODD, 04839 p->style->Keepaway); 04840 } 04841 if (rip) 04842 { 04843 if (TEST_FLAG (LIVEROUTEFLAG, PCB)) 04844 ripout_livedraw_obj (p); 04845 #ifndef NDEBUG 04846 del = 04847 #endif 04848 r_delete_entry (rd->layergrouptree[p->group], 04849 &p->box); 04850 #ifndef NDEBUG 04851 assert (del); 04852 #endif 04853 } 04854 else 04855 { 04856 p->flags.is_odd = AutoRouteParameters.is_odd; 04857 } 04858 } 04859 END_LOOP; 04860 if (TEST_FLAG (LIVEROUTEFLAG, PCB)) 04861 Draw (); 04862 /* reset to original connectivity */ 04863 if (rip) 04864 { 04865 ras.ripped++; 04866 ResetSubnet (net); 04867 } 04868 else 04869 { 04870 heap_insert (next_pass, 0, net); 04871 continue; 04872 } 04873 } 04874 /* count number of subnets */ 04875 FOREACH_SUBNET (net, p); 04876 ras.total_subnets++; 04877 END_FOREACH (net, p); 04878 /* the first subnet doesn't require routing. */ 04879 ras.total_subnets--; 04880 /* and re-route! */ 04881 total_net_cost = 0; 04882 /* only route that which isn't fully routed */ 04883 #ifdef ROUTE_DEBUG 04884 if (ras.total_subnets == 0 || aabort) 04885 #else 04886 if (ras.total_subnets == 0) 04887 #endif 04888 { 04889 heap_insert (next_pass, 0, net); 04890 continue; 04891 } 04892 04893 /* the loop here ensures that we get to all subnets even if 04894 * some of them are unreachable from the first subnet. */ 04895 LIST_LOOP (net, same_net, p); 04896 { 04897 #ifdef NET_HEAP 04898 BoxType b = shrink_routebox (p); 04899 /* using a heap allows us to start from smaller objects and 04900 * end at bigger ones. also prefer to start at planes, then pads */ 04901 heap_insert (net_heap, (float) (b.X2 - b.X1) * 04902 #if defined(ROUTE_RANDOMIZED) 04903 (0.3 + rand () / (RAND_MAX + 1.0)) * 04904 #endif 04905 (b.Y2 - b.Y1) * (p->type == PLANE ? 04906 -1 : (p->type == 04907 PAD ? 1 : 10)), p); 04908 } 04909 END_LOOP; 04910 ros.net_completely_routed = 0; 04911 while (!heap_is_empty (net_heap)) 04912 { 04913 p = (routebox_t *) heap_remove_smallest (net_heap); 04914 #endif 04915 if (!p->flags.fixed || p->flags.subnet_processed || 04916 p->type == OTHER) 04917 continue; 04918 04919 while (!ros.net_completely_routed) 04920 { 04921 double percent; 04922 04923 assert (no_expansion_boxes (rd)); 04924 /* FIX ME: the number of edges to examine should be in autoroute parameters 04925 * i.e. the 2000 and 800 hard-coded below should be controllable by the user 04926 */ 04927 ros = 04928 RouteOne (rd, p, NULL, 04929 ((AutoRouteParameters. 04930 is_smoothing ? 2000 : 800) * (i + 04931 1)) * 04932 routing_layers); 04933 total_net_cost += ros.best_route_cost; 04934 if (ros.found_route) 04935 { 04936 if (ros.route_had_conflicts) 04937 ras.conflict_subnets++; 04938 else 04939 { 04940 ras.routed_subnets++; 04941 ras.total_nets_routed++; 04942 } 04943 } 04944 else 04945 { 04946 if (!ros.net_completely_routed) 04947 ras.failed++; 04948 /* don't bother trying any other source in this subnet */ 04949 LIST_LOOP (p, same_subnet, pp); 04950 pp->flags.subnet_processed = 1; 04951 END_LOOP; 04952 break; 04953 } 04954 /* note that we can infer nothing about ras.total_subnets based 04955 * on the number of calls to RouteOne, because we may be unable 04956 * to route a net from a particular starting point, but perfectly 04957 * able to route it from some other. */ 04958 percent = calculate_progress (this_heap_item, this_heap_size, &ras); 04959 request_cancel = gui->progress (percent * 100., 100, 04960 _("Autorouting tracks")); 04961 if (request_cancel) 04962 { 04963 ras.total_nets_routed = 0; 04964 ras.conflict_subnets = 0; 04965 Message ("Autorouting cancelled\n"); 04966 goto out; 04967 } 04968 } 04969 } 04970 #ifndef NET_HEAP 04971 END_LOOP; 04972 #endif 04973 if (!ros.net_completely_routed) 04974 net->flags.is_bad = 1; /* don't skip this the next round */ 04975 04976 /* Route easiest nets from this pass first on next pass. 04977 * This works best because it's likely that the hardest 04978 * is the last one routed (since it has the most obstacles) 04979 * but it will do no good to rip it up and try it again 04980 * without first changing any of the other routes 04981 */ 04982 heap_insert (next_pass, total_net_cost, net); 04983 if (total_net_cost < EXPENSIVE) 04984 this_cost += total_net_cost; 04985 /* reset subnet_processed flags */ 04986 LIST_LOOP (net, same_net, p); 04987 { 04988 p->flags.subnet_processed = 0; 04989 } 04990 END_LOOP; 04991 } 04992 /* swap this_pass and next_pass and do it all over again! */ 04993 ro = 0; 04994 assert (heap_is_empty (this_pass)); 04995 tmp = this_pass; 04996 this_pass = next_pass; 04997 next_pass = tmp; 04998 #if defined(ROUTE_DEBUG) || defined (ROUTE_VERBOSE) 04999 printf 05000 ("END OF PASS %d: %d/%d subnets routed without conflicts at cost %.0f, %d conflicts, %d failed %d ripped\n", 05001 i, ras.routed_subnets, ras.total_subnets, this_cost, 05002 ras.conflict_subnets, ras.failed, ras.ripped); 05003 #endif 05004 #ifdef ROUTE_DEBUG 05005 if (aabort) 05006 break; 05007 #endif 05008 /* if no conflicts found, skip directly to smoothing pass! */ 05009 if (ras.conflict_subnets == 0 && ras.routed_subnets == ras.total_subnets 05010 && i <= passes) 05011 i = passes - (smoothes ? 0 : 1); 05012 /* if no changes in a smoothing round, then we're done */ 05013 if (this_cost == last_cost && i > passes && i < passes + smoothes) 05014 i = passes + smoothes - 1; 05015 last_cost = this_cost; 05016 this_cost = 0; 05017 } 05018 05019 Message ("%d of %d nets successfully routed.\n", 05020 ras.routed_subnets, ras.total_subnets); 05021 05022 out: 05023 heap_destroy (&this_pass); 05024 heap_destroy (&next_pass); 05025 #ifdef NET_HEAP 05026 heap_destroy (&net_heap); 05027 #endif 05028 05029 /* no conflicts should be left at the end of the process. */ 05030 assert (ras.conflict_subnets == 0); 05031 05032 return ras; 05033 } 05034 05035 struct fpin_info 05036 { 05037 PinType *pin; 05038 Coord X, Y; 05039 jmp_buf env; 05040 }; 05041 05042 static int 05043 fpin_rect (const BoxType * b, void *cl) 05044 { 05045 PinType *pin = (PinType *) b; 05046 struct fpin_info *info = (struct fpin_info *) cl; 05047 if (pin->X == info->X && pin->Y == info->Y) 05048 { 05049 info->pin = (PinType *) b; 05050 longjmp (info->env, 1); 05051 } 05052 return 0; 05053 } 05054 05055 static int 05056 FindPin (const BoxType * box, PinType ** pin) 05057 { 05058 struct fpin_info info; 05059 05060 info.pin = NULL; 05061 info.X = box->X1; 05062 info.Y = box->Y1; 05063 if (setjmp (info.env) == 0) 05064 r_search (PCB->Data->pin_tree, box, NULL, fpin_rect, &info); 05065 else 05066 { 05067 *pin = info.pin; 05068 return PIN_TYPE; 05069 } 05070 if (setjmp (info.env) == 0) 05071 r_search (PCB->Data->via_tree, box, NULL, fpin_rect, &info); 05072 else 05073 { 05074 *pin = info.pin; 05075 return VIA_TYPE; 05076 } 05077 *pin = NULL; 05078 return NO_TYPE; 05079 } 05080 05081 05087 bool 05088 IronDownAllUnfixedPaths (routedata_t * rd) 05089 { 05090 bool changed = false; 05091 LayerType *layer; 05092 routebox_t *net, *p; 05093 int i; 05094 LIST_LOOP (rd->first_net, different_net, net); 05095 { 05096 LIST_LOOP (net, same_net, p); 05097 { 05098 if (!p->flags.fixed) 05099 { 05100 /* find first on layer in this group */ 05101 assert (PCB->LayerGroups.Number[p->group] > 0); 05102 assert (is_layer_group_active[p->group]); 05103 for (i = 0, layer = NULL; i < PCB->LayerGroups.Number[p->group]; 05104 i++) 05105 { 05106 layer = LAYER_PTR (PCB->LayerGroups.Entries[p->group][i]); 05107 if (layer->On) 05108 break; 05109 } 05110 assert (layer && layer->On); /*at least one layer must be on in this group! */ 05111 assert (p->type != EXPANSION_AREA); 05112 if (p->type == LINE) 05113 { 05114 Coord halfwidth = HALF_THICK (p->style->Thick); 05115 double th = halfwidth * 2 + 1; 05116 BoxType b; 05117 assert (p->parent.line == NULL); 05118 /* orthogonal; thickness is 2*halfwidth */ 05119 /* flip coordinates, if bl_to_ur */ 05120 b = p->sbox; 05121 total_wire_length += hypot (b.X2 - b.X1 - th, b.Y2 - b.Y1 - th); 05122 b = shrink_box (&b, halfwidth); 05123 if (b.X2 == b.X1 + 1) 05124 b.X2 = b.X1; 05125 if (b.Y2 == b.Y1 + 1) 05126 b.Y2 = b.Y1; 05127 if (p->flags.bl_to_ur) 05128 { 05129 Coord t; 05130 t = b.X1; 05131 b.X1 = b.X2; 05132 b.X2 = t; 05133 } 05134 /* using CreateDrawn instead of CreateNew concatenates sequential lines */ 05135 p->parent.line = CreateDrawnLineOnLayer 05136 (layer, b.X1, b.Y1, b.X2, b.Y2, 05137 p->style->Thick, 05138 p->style->Keepaway * 2, 05139 MakeFlags (AUTOFLAG | 05140 (TEST_FLAG (CLEARNEWFLAG, PCB) ? CLEARLINEFLAG : 05141 0))); 05142 05143 if (p->parent.line) 05144 { 05145 AddObjectToCreateUndoList (LINE_TYPE, layer, 05146 p->parent.line, p->parent.line); 05147 changed = true; 05148 } 05149 } 05150 else if (p->type == VIA || p->type == VIA_SHADOW) 05151 { 05152 routebox_t *pp = 05153 (p->type == VIA_SHADOW) ? p->parent.via_shadow : p; 05154 Coord radius = HALF_THICK (pp->style->Diameter); 05155 BoxType b = shrink_routebox (p); 05156 total_via_count++; 05157 assert (pp->type == VIA); 05158 if (pp->parent.via == NULL) 05159 { 05160 assert (b.X1 + radius == b.X2 - radius); 05161 assert (b.Y1 + radius == b.Y2 - radius); 05162 pp->parent.via = 05163 CreateNewVia (PCB->Data, b.X1 + radius, 05164 b.Y1 + radius, 05165 pp->style->Diameter, 05166 2 * pp->style->Keepaway, 05167 0, pp->style->Hole, NULL, 05168 MakeFlags (AUTOFLAG)); 05169 assert (pp->parent.via); 05170 if (pp->parent.via) 05171 { 05172 AddObjectToCreateUndoList (VIA_TYPE, 05173 pp->parent.via, 05174 pp->parent.via, 05175 pp->parent.via); 05176 changed = true; 05177 } 05178 } 05179 assert (pp->parent.via); 05180 if (p->type == VIA_SHADOW) 05181 { 05182 p->type = VIA; 05183 p->parent.via = pp->parent.via; 05184 } 05185 } 05186 else if (p->type == THERMAL) 05187 /* nothing to do because, the via might not be there yet */ ; 05188 else 05189 assert (0); 05190 } 05191 } 05192 END_LOOP; 05193 /* loop again to place all the thermals now that the vias are down */ 05194 LIST_LOOP (net, same_net, p); 05195 { 05196 if (p->type == THERMAL) 05197 { 05198 PinType *pin = NULL; 05199 /* thermals are alread a single point search, no need to shrink */ 05200 int type = FindPin (&p->box, &pin); 05201 if (pin) 05202 { 05203 AddObjectToClearPolyUndoList (type, 05204 pin->Element ? pin->Element : pin, 05205 pin, pin, false); 05206 RestoreToPolygon (PCB->Data, VIA_TYPE, LAYER_PTR (p->layer), 05207 pin); 05208 AddObjectToFlagUndoList (type, 05209 pin->Element ? pin->Element : pin, pin, 05210 pin); 05211 ASSIGN_THERM (p->layer, PCB->ThermStyle, pin); 05212 AddObjectToClearPolyUndoList (type, 05213 pin->Element ? pin->Element : pin, 05214 pin, pin, true); 05215 ClearFromPolygon (PCB->Data, VIA_TYPE, LAYER_PTR (p->layer), 05216 pin); 05217 changed = true; 05218 } 05219 } 05220 } 05221 END_LOOP; 05222 } 05223 END_LOOP; 05224 return changed; 05225 } 05226 05227 bool 05228 AutoRoute (bool selected) 05229 { 05230 bool changed = false; 05231 routedata_t *rd; 05232 int i; 05233 05234 total_wire_length = 0; 05235 total_via_count = 0; 05236 05237 #ifdef ROUTE_DEBUG 05238 ddraw = gui->request_debug_draw (); 05239 if (ddraw != NULL) 05240 { 05241 ar_gc = ddraw->make_gc (); 05242 ddraw->set_line_cap (ar_gc, Round_Cap); 05243 } 05244 #endif 05245 05246 for (i = 0; i < NUM_STYLES; i++) 05247 { 05248 if (PCB->RouteStyle[i].Thick == 0 || 05249 PCB->RouteStyle[i].Diameter == 0 || 05250 PCB->RouteStyle[i].Hole == 0 || PCB->RouteStyle[i].Keepaway == 0) 05251 { 05252 Message ("You must define proper routing styles\n" 05253 "before auto-routing.\n"); 05254 return (false); 05255 } 05256 } 05257 if (PCB->Data->RatN == 0) 05258 return (false); 05259 rd = CreateRouteData (); 05260 05261 if (1) 05262 { 05263 routebox_t *net, *rb, *last; 05264 int i = 0; 05265 /* count number of rats selected */ 05266 RAT_LOOP (PCB->Data); 05267 { 05268 if (!selected || TEST_FLAG (SELECTEDFLAG, line)) 05269 i++; 05270 } 05271 END_LOOP; 05272 #ifdef ROUTE_VERBOSE 05273 printf ("%d nets!\n", i); 05274 #endif 05275 if (i == 0) 05276 goto donerouting; /* nothing to do here */ 05277 /* if only one rat selected, do things the quick way. =) */ 05278 if (i == 1) 05279 { 05280 RAT_LOOP (PCB->Data); 05281 if (!selected || TEST_FLAG (SELECTEDFLAG, line)) 05282 { 05283 /* look up the end points of this rat line */ 05284 routebox_t *a = 05285 FindRouteBoxOnLayerGroup (rd, line->Point1.X, 05286 line->Point1.Y, line->group1); 05287 routebox_t *b = 05288 FindRouteBoxOnLayerGroup (rd, line->Point2.X, 05289 line->Point2.Y, line->group2); 05290 05291 /* If the rat starts or ends at a non-straight pad (i.e., at a 05292 * rotated SMD), a or b will be NULL since the autorouter can't 05293 * handle these. 05294 */ 05295 if (a != NULL && b != NULL) 05296 { 05297 assert (a->style == b->style); 05298 /* route exactly one net, without allowing conflicts */ 05299 InitAutoRouteParameters (0, a->style, false, true, true); 05300 /* hace planes work better as sources than targets */ 05301 changed = RouteOne (rd, a, b, 150000).found_route || changed; 05302 goto donerouting; 05303 } 05304 } 05305 END_LOOP; 05306 } 05307 /* otherwise, munge the netlists so that only the selected rats 05308 * get connected. */ 05309 /* first, separate all sub nets into separate nets */ 05310 /* note that this code works because LIST_LOOP is clever enough not to 05311 * be fooled when the list is changing out from under it. */ 05312 last = NULL; 05313 LIST_LOOP (rd->first_net, different_net, net); 05314 { 05315 FOREACH_SUBNET (net, rb); 05316 { 05317 if (last) 05318 { 05319 last->different_net.next = rb; 05320 rb->different_net.prev = last; 05321 } 05322 last = rb; 05323 } 05324 END_FOREACH (net, rb); 05325 LIST_LOOP (net, same_net, rb); 05326 { 05327 rb->same_net = rb->same_subnet; 05328 } 05329 END_LOOP; 05330 /* at this point all nets are equal to their subnets */ 05331 } 05332 END_LOOP; 05333 if (last) 05334 { 05335 last->different_net.next = rd->first_net; 05336 rd->first_net->different_net.prev = last; 05337 } 05338 05339 /* now merge only those subnets connected by a rat line */ 05340 RAT_LOOP (PCB->Data); 05341 if (!selected || TEST_FLAG (SELECTEDFLAG, line)) 05342 { 05343 /* look up the end points of this rat line */ 05344 routebox_t *a; 05345 routebox_t *b; 05346 a = 05347 FindRouteBoxOnLayerGroup (rd, line->Point1.X, 05348 line->Point1.Y, line->group1); 05349 b = 05350 FindRouteBoxOnLayerGroup (rd, line->Point2.X, 05351 line->Point2.Y, line->group2); 05352 if (!a || !b) 05353 { 05354 #ifdef DEBUG_STALE_RATS 05355 AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line); 05356 ASSIGN_FLAG (SELECTEDFLAG, true, line); 05357 DrawRat (line, 0); 05358 #endif /* DEBUG_STALE_RATS */ 05359 Message ("The rats nest is stale! Aborting autoroute...\n"); 05360 goto donerouting; 05361 } 05362 /* merge subnets into a net! */ 05363 MergeNets (a, b, NET); 05364 } 05365 END_LOOP; 05366 /* now 'different_net' may point to too many different nets. Reset. */ 05367 LIST_LOOP (rd->first_net, different_net, net); 05368 { 05369 if (!net->flags.touched) 05370 { 05371 LIST_LOOP (net, same_net, rb); 05372 rb->flags.touched = 1; 05373 END_LOOP; 05374 } 05375 else /* this is not a "different net"! */ 05376 RemoveFromNet (net, DIFFERENT_NET); 05377 } 05378 END_LOOP; 05379 /* reset "touched" flag */ 05380 LIST_LOOP (rd->first_net, different_net, net); 05381 { 05382 LIST_LOOP (net, same_net, rb); 05383 { 05384 assert (rb->flags.touched); 05385 rb->flags.touched = 0; 05386 } 05387 END_LOOP; 05388 } 05389 END_LOOP; 05390 } 05391 /* okay, rd's idea of netlist now corresponds to what we want routed */ 05392 /* auto-route all nets */ 05393 changed = (RouteAll (rd).total_nets_routed > 0) || changed; 05394 donerouting: 05395 gui->progress (0, 0, NULL); 05396 if (TEST_FLAG (LIVEROUTEFLAG, PCB)) 05397 { 05398 int i; 05399 BoxType big = {0, 0, MAX_COORD, MAX_COORD}; 05400 for (i = 0; i < max_group; i++) 05401 { 05402 r_search (rd->layergrouptree[i], &big, NULL, ripout_livedraw_obj_cb, NULL); 05403 } 05404 } 05405 #ifdef ROUTE_DEBUG 05406 if (ddraw != NULL) 05407 { 05408 ddraw->destroy_gc (ar_gc); 05409 gui->finish_debug_draw (); 05410 } 05411 #endif 05412 05413 if (changed) 05414 changed = IronDownAllUnfixedPaths (rd); 05415 Message ("Total added wire length = %$mS, %d vias added\n", 05416 (Coord) total_wire_length, total_via_count); 05417 DestroyRouteData (&rd); 05418 if (changed) 05419 { 05420 SaveUndoSerialNumber (); 05421 05422 /* optimize rats, we've changed connectivity a lot. */ 05423 DeleteRats (false /*all rats */ ); 05424 RestoreUndoSerialNumber (); 05425 AddAllRats (false /*all rats */ , NULL); 05426 RestoreUndoSerialNumber (); 05427 05428 IncrementUndoSerialNumber (); 05429 05430 Redraw (); 05431 } 05432 #if defined (ROUTE_DEBUG) 05433 aabort = 0; 05434 #endif 05435 return (changed); 05436 }