1 /*
2 * Copyright (C) 2007 Bill Cox
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
17 */
18
19 /*--------------------------------------------------------------------------------------------------
20 This module routes the schema. There is a grid consisting of "Bundles", or bunds representing
21 locations in the grid. There are horizontal and vertical tracks of bunds that overlap. In
22 horizontal tracks, adjacencies are build horizontally, but not vertically. When horizontal
23 tracks cross vertical tracks, there are adjacencies between the overlapping horizontal and
24 vertical bundles.
25 --------------------------------------------------------------------------------------------------*/
26 #include "dw.h"
27
28 static uint32 dwOverconstraints;
29 static uint32 dwRows, dwCols;
30 static uint32 dwOverconstraintPenalty;
31 static uint32 dwMaxBucket;
32 static dvClass dwSourceClass, dwTargetClass;
33 static dwBundArray dwRandBunds;
34 static dwRelationshipArray dwRandRelationships;
35
36 #define dwIndexHBund(x, y) dwIndex2Bund(dwCols*(y) + (x))
37 #define dwIndexVBund(x, y) dwIndex2Bund(dwRows*dwCols + dwRows*(x) + (y))
38
39 /* Bund adj iterator */
40 #define dwFindAdjOtherBund(adj, bund) (dwAdjGetFromBund(adj) == (bund) ? \
41 dwAdjGetToBund(adj) : dwAdjGetFromBund(adj))
42 #define dwBundGetFirstAdj(bund) (dwBundGetFirstInAdj(bund) != dwAdjNull? \
43 dwBundGetFirstInAdj(bund) : dwBundGetFirstOutAdj(bund))
44 #define dwBundGetNextBundAdj(bund, adj) (dwAdjGetToBund(adj) == (bund)? \
45 (dwAdjGetNextBundInAdj(adj) != dwAdjNull? \
46 dwAdjGetNextBundInAdj(adj) : dwBundGetFirstOutAdj(bund)) : \
47 dwAdjGetNextBundOutAdj(adj))
48 #define dwForeachBundAdj(bund, adj) \
49 for(adj = dwBundGetFirstAdj(bund); (adj != dwAdjNull); \
50 adj = dwBundGetNextBundAdj(bund, adj))
51 #define dwEndBundAdj
52
53 /*--------------------------------------------------------------------------------------------------
54 Create a new bundle.
55 --------------------------------------------------------------------------------------------------*/
dwBundCreate(uint32 x,uint32 y)56 static dwBund dwBundCreate(
57 uint32 x,
58 uint32 y)
59 {
60 dwBund bund = dwBundAlloc();
61
62 dwBundSetX(bund, x);
63 dwBundSetY(bund, y);
64 return bund;
65 }
66
67 /*--------------------------------------------------------------------------------------------------
68 Create a new adj.
69 --------------------------------------------------------------------------------------------------*/
dwAdjCreate(dwBund bund1,dwBund bund2)70 static dwAdj dwAdjCreate(
71 dwBund bund1,
72 dwBund bund2)
73 {
74 dwAdj adj = dwAdjAlloc();
75
76 dwBundInsertOutAdj(bund1, adj);
77 dwBundInsertInAdj(bund2, adj);
78 return adj;
79 }
80
81 /*--------------------------------------------------------------------------------------------------
82 Build the routing graph of horizontal and vertical tracks of bundles. We create first horizontal
83 bundles from lower left to the top, then vertical tracks from lower left to the right.
84
85 gridsPerCol = dwSchemaGetColWidth(schema)
86 gridsPerRow = dwSchemaGetRowHeight(schema)
87 cols = (dwSchemaGetCols(schema) + 1)*dwGridsPerCol
88 rows = (dwSchemaGetRows(schema) + 1)*dwGridsPerRow
89 hBundIndex = bundY*cols + bundX
90 vBundIndex = rows*cols + bundX*rows + bundY
91 --------------------------------------------------------------------------------------------------*/
buildRoutingGraph(dvSchema schema)92 static void buildRoutingGraph(
93 dvSchema schema)
94 {
95 dwBund bund, prevBund, hBund;
96 uint32 gridsPerCol = dwSchemaGetColWidth(schema);
97 uint32 gridsPerRow = dwSchemaGetRowHeight(schema);
98 uint32 x, y;
99
100 dwCols = (dwSchemaGetCols(schema) + 1)*gridsPerCol;
101 dwRows = (dwSchemaGetRows(schema) + 1)*gridsPerRow;
102 /* Build horizontal tracks */
103 for(y = 0; y < dwRows; y++) {
104 prevBund = dwBundNull;
105 for(x = 0; x < dwCols; x++) {
106 bund = dwBundCreate(x, y);
107 if(prevBund != dwBundNull) {
108 dwAdjCreate(prevBund, bund);
109 }
110 prevBund = bund;
111 }
112 }
113 /* Build vertical tracks */
114 for(x = 0; x < dwCols; x++) {
115 prevBund = dwBundNull;
116 for(y = 0; y < dwRows; y++) {
117 bund = dwBundCreate(x, y);
118 if(prevBund != dwBundNull) {
119 dwAdjCreate(prevBund, bund);
120 }
121 /* Connect this vertical bund to it's overlapping horizontal bund */
122 hBund = dwIndexHBund(x, y);
123 dwAdjCreate(bund, hBund);
124 dwBundSetOverlappingBund(bund, hBund);
125 dwBundSetOverlappingBund(hBund, bund);
126 prevBund = bund;
127 }
128 }
129 }
130
131 /*--------------------------------------------------------------------------------------------------
132 Add the bundle to the class, and then block all adjacencies to the bundle, exept in the direction
133 specified.
134 --------------------------------------------------------------------------------------------------*/
addClassBund(dvClass theClass,dwBund bund,uint32 x,uint32 y)135 static void addClassBund(
136 dvClass theClass,
137 dwBund bund,
138 uint32 x,
139 uint32 y)
140 {
141 dwBund otherBund;
142 dwAdj adj;
143
144 dwClassInsertBund(theClass, bund);
145 dwForeachBundAdj(bund, adj) {
146 otherBund = dwFindAdjOtherBund(adj, bund);
147 if(dwBundGetX(otherBund) != x || dwBundGetY(otherBund) != y) {
148 dwAdjSetBlocked(adj, true);
149 }
150 } dwEndBundAdj;
151 }
152
153 /*--------------------------------------------------------------------------------------------------
154 Add the Class --> Bund relationship for this class. Also set the class's bounding box in grid
155 units.
156 --------------------------------------------------------------------------------------------------*/
addClassToGraph(dvSchema schema,dvClass theClass)157 static void addClassToGraph(
158 dvSchema schema,
159 dvClass theClass)
160 {
161 dwBund bund;
162 uint32 width = dwClassGetWidth(theClass);
163 uint32 height = dwClassGetHeight(theClass);
164 uint32 gridsPerCol = dwSchemaGetColWidth(schema);
165 uint32 gridsPerRow = dwSchemaGetRowHeight(schema);
166 uint32 x = (dwClassGetX(theClass) + 1)*gridsPerCol - (width >> 1);
167 uint32 y = (dwClassGetY(theClass) + 1)*gridsPerRow - (height >> 1);
168 uint32 dX, dY;
169
170 /* In case we had a previous run, the class could be pointing to a deleted bundle */
171 dwClassSetFirstBund(theClass, dwBundNull);
172 dwClassSetLeft(theClass, x);
173 dwClassSetBottom(theClass, y);
174 dwClassSetRight(theClass, x + width);
175 dwClassSetTop(theClass, y + height);
176 /* Add the top and bottom to the vertical grid. */
177 for(dX = 0; dX <= width; dX++) {
178 bund = dwIndexVBund(x + dX, y);
179 addClassBund(theClass, bund, x + dX, y - 1);
180 bund = dwIndexVBund(x + dX, y + height);
181 addClassBund(theClass, bund, x + dX, y + height + 1);
182 }
183 /* Add the left and right to the horizontal grid. */
184 for(dY = 0; dY <= height; dY++) {
185 bund = dwIndexHBund(x, y + dY);
186 addClassBund(theClass, bund, x - 1, y + dY);
187 bund = dwIndexHBund(x + width, y + dY);
188 addClassBund(theClass, bund, x + width + 1, y + dY);
189 }
190 }
191
192 /*--------------------------------------------------------------------------------------------------
193 Mark bundles within 2 adjs of a class as nearby. This effects the cost for routing.
194 --------------------------------------------------------------------------------------------------*/
markBundsNearClass(dvClass theClass)195 static void markBundsNearClass(
196 dvClass theClass)
197 {
198 dwBund bund1, bund2;
199 dwAdj adj1;
200
201 dwForeachClassBund(theClass, bund1) {
202 dwForeachBundAdj(bund1, adj1) {
203 bund2 = dwFindAdjOtherBund(adj1, bund1);
204 dwBundSetNearClass(bund2, true);
205 } dwEndBundAdj;
206 } dwEndClassBund;
207 }
208
209 /*--------------------------------------------------------------------------------------------------
210 Build the Class --> Bund relationship for all classes in the schema.
211 --------------------------------------------------------------------------------------------------*/
addClassesToGraph(dvSchema schema)212 static void addClassesToGraph(
213 dvSchema schema)
214 {
215 dvClass theClass;
216
217 dwForeachClassArrayClass(dwClasses, theClass) {
218 addClassToGraph(schema, theClass);
219 markBundsNearClass(theClass);
220 } dwEndClassArrayClass;
221 }
222
223 /*--------------------------------------------------------------------------------------------------
224 Add the bundle to the bunket with the given cost.
225 --------------------------------------------------------------------------------------------------*/
addBucketBund(uint32 cost,dwBund bund)226 static void addBucketBund(
227 uint32 cost,
228 dwBund bund)
229 {
230 dwBucket bucket;
231
232 utAssert(dwBundGetClass(bund) == dwSourceClass || dwBundGetPrevBund(bund) != dwBundNull);
233 while(cost >= dwUsedBucket()) {
234 (void)dwBucketAlloc();
235 }
236 bucket = dwIndex2Bucket(cost);
237 dwBucketInsertBund(bucket, bund);
238 dwMaxBucket = utMax(cost, dwMaxBucket);
239 }
240
241 /*--------------------------------------------------------------------------------------------------
242 Find a bundle cost. It's more expensive to be overconstrained, or close to a class or another
243 relationship.
244 --------------------------------------------------------------------------------------------------*/
findBundCost(dwBund bund)245 static uint32 findBundCost(
246 dwBund bund)
247 {
248 dwBund overlappingBund = dwBundGetOverlappingBund(bund);
249 uint32 cost = 0;
250
251 if(dwBundGetFirstRoute(bund) != dwRouteNull) {
252 cost = dwOverconstraintPenalty;
253 }
254 if(dwBundGetFirstRoute(overlappingBund) != dwRouteNull) {
255 cost++;
256 }
257 if(dwBundNearClass(bund) || dwBundNearClass(overlappingBund)) {
258 cost += 4;
259 }
260 return cost;
261 }
262
263 /*--------------------------------------------------------------------------------------------------
264 Initialize the wave on the source class.
265 --------------------------------------------------------------------------------------------------*/
initWave(void)266 static void initWave(void)
267 {
268 dwBund bund;
269 uint32 cost;
270
271 dwForeachClassBund(dwSourceClass, bund) {
272 cost = findBundCost(bund);
273 dwBundSetPrevBund(bund, dwBundNull);
274 addBucketBund(cost, bund);
275 } dwEndClassBund;
276 }
277
278 /*--------------------------------------------------------------------------------------------------
279 Initialize the wave on the source class for a self-relationship. Just find a random starting
280 point.
281 --------------------------------------------------------------------------------------------------*/
initSelfWave(void)282 static void initSelfWave(void)
283 {
284 dwBund bund, randSourceBund;
285 uint32 xRandBund;
286
287 dwBundArraySetUsedBund(dwRandBunds, 0);
288 dwForeachClassBund(dwSourceClass, bund) {
289 dwBundSetPrevBund(bund, dwBundNull);
290 if(dwBundGetFirstRoute(bund) == dwRouteNull) {
291 dwBundArrayAppendBund(dwRandBunds, bund);
292 }
293 } dwEndClassBund;
294 xRandBund = utRandN(dwBundArrayGetUsedBund(dwRandBunds));
295 randSourceBund = dwBundArrayGetiBund(dwRandBunds, xRandBund);
296 addBucketBund(0, randSourceBund);
297 }
298
299 /*--------------------------------------------------------------------------------------------------
300 Randomize bundles in the bucket, and add them to the dwRandBunds array.
301 --------------------------------------------------------------------------------------------------*/
randomizeBundArray(dwBundArray bunds)302 static void randomizeBundArray(
303 dwBundArray bunds)
304 {
305 dwBund bund, otherBund;
306 uint32 xBund, xOtherBund;
307 uint32 numBunds = dwBundArrayGetUsedBund(bunds);
308
309 for(xBund = 0; xBund < numBunds; xBund++) {
310 xOtherBund = xBund + utRandN(numBunds - xBund);
311 bund = dwBundArrayGetiBund(bunds, xBund);
312 otherBund = dwBundArrayGetiBund(bunds, xOtherBund);
313 dwBundArraySetiBund(bunds, xBund, otherBund);
314 dwBundArraySetiBund(bunds, xOtherBund, bund);
315 }
316 }
317
318 /*--------------------------------------------------------------------------------------------------
319 Randomize bundles in the bucket, and add them to the dwRandBunds array.
320 --------------------------------------------------------------------------------------------------*/
randomizeBunds(dwBucket bucket)321 static void randomizeBunds(
322 dwBucket bucket)
323 {
324 dwBund bund;
325
326 dwBundArraySetUsedBund(dwRandBunds, 0);
327 dwForeachBucketBund(bucket, bund) {
328 dwBundArrayAppendBund(dwRandBunds, bund);
329 } dwEndBucketBund;
330 randomizeBundArray(dwRandBunds);
331 }
332
333 /*--------------------------------------------------------------------------------------------------
334 Expand the bundle into nearest neighbors randomly. If we find a target bund, return it.
335 --------------------------------------------------------------------------------------------------*/
expandBund(dwBund bund)336 static dwBund expandBund(
337 dwBund bund)
338 {
339 dvClass theClass;
340 dwBund otherBund;
341 dwAdj adj;
342 uint32 cost = dwBucket2Index(dwBundGetBucket(bund)) + 1;
343 uint32 bundCost;
344
345 dwForeachBundAdj(bund, adj) {
346 otherBund = dwFindAdjOtherBund(adj, bund);
347 if(dwBundGetBucket(otherBund) == dwBucketNull && !dwAdjBlocked(adj)) {
348 theClass = dwBundGetClass(otherBund);
349 if(theClass == dwTargetClass) {
350 dwBundSetPrevBund(otherBund, bund);
351 return otherBund;
352 }
353 if(theClass == dvClassNull) {
354 bundCost = cost + findBundCost(otherBund);
355 dwBundSetPrevBund(otherBund, bund);
356 addBucketBund(bundCost, otherBund);
357 }
358 }
359 } dwEndBundAdj;
360 return dwBundNull;
361 }
362
363 /*--------------------------------------------------------------------------------------------------
364 Expand the bucket of bundles into nearest neighbors randomly. Return any target we find.
365 --------------------------------------------------------------------------------------------------*/
expandBucket(dwBucket bucket)366 static dwBund expandBucket(
367 dwBucket bucket)
368 {
369 dwBund bund, targetBund;
370
371 randomizeBunds(bucket);
372 dwForeachBundArrayBund(dwRandBunds, bund) {
373 targetBund = expandBund(bund);
374 if(targetBund != dwBundNull) {
375 return targetBund;
376 }
377 } dwEndBundArrayBund;
378 return dwBundNull;
379 }
380
381 /*--------------------------------------------------------------------------------------------------
382 Expand the wave to the target. Return the target we hit.
383 --------------------------------------------------------------------------------------------------*/
expandToTarget(void)384 static dwBund expandToTarget(void)
385 {
386 dwBucket bucket;
387 dwBund target;
388
389 uint32 xBucket = 0;
390
391 while(true) {
392 bucket = dwIndex2Bucket(xBucket);
393 target = expandBucket(bucket);
394 if(target != dwBundNull) {
395 return target;
396 }
397 xBucket++;
398 }
399 return dwBundNull; /* Dummy return */
400 }
401
402 /*--------------------------------------------------------------------------------------------------
403 Follow the back pointers from the target to source, building routes.
404 --------------------------------------------------------------------------------------------------*/
dwBuildRoute(dvRelationship relationship,dwBund bund)405 static dwRoute dwBuildRoute(
406 dvRelationship relationship,
407 dwBund bund)
408 {
409 dwRoute route = dwRouteAlloc();
410
411 if(dwBundGetFirstRoute(bund) != dwRouteNull) {
412 dwOverconstraints++;
413 }
414 dwRelationshipInsertRoute(relationship, route);
415 dwBundInsertRoute(bund, route);
416 return route;
417 }
418
419 /*--------------------------------------------------------------------------------------------------
420 Follow the back pointers from the target to source, building routes.
421 --------------------------------------------------------------------------------------------------*/
backtrace(dvRelationship relationship,dwBund bund)422 static void backtrace(
423 dvRelationship relationship,
424 dwBund bund)
425 {
426 dwRoute route;
427
428 do {
429 route = dwBuildRoute(relationship, bund);
430 bund = dwBundGetPrevBund(bund);
431 } while(bund != dwBundNull);
432 }
433
434 /*--------------------------------------------------------------------------------------------------
435 Empty buckets so we can do another expansion.
436 --------------------------------------------------------------------------------------------------*/
emptyBuckets(void)437 static void emptyBuckets(void)
438 {
439 dwBucket bucket;
440 dwBund bund;
441 uint32 xBucket;
442
443 for(xBucket = 0; xBucket <= dwMaxBucket; xBucket++) {
444 bucket = dwIndex2Bucket(xBucket);
445 utDo {
446 bund = dwBucketGetFirstBund(bucket);
447 } utWhile(bund != dwBundNull) {
448 dwBucketRemoveBund(bucket, bund);
449 } utRepeat;
450 }
451 }
452
453 /*--------------------------------------------------------------------------------------------------
454 Route a relationship.
455 --------------------------------------------------------------------------------------------------*/
routeRelationship(dvRelationship relationship)456 static void routeRelationship(
457 dvRelationship relationship)
458 {
459 dwBund target;
460
461 dwSourceClass = dvRelationshipGetParentClass(relationship);
462 dwTargetClass = dvRelationshipGetChildClass(relationship);
463 dwMaxBucket = 0;
464 if(dwSourceClass != dwTargetClass) {
465 initWave();
466 } else {
467 initSelfWave();
468 }
469 target = expandToTarget();
470 backtrace(relationship, target);
471 emptyBuckets();
472 }
473
474 /*--------------------------------------------------------------------------------------------------
475 Create an initial solution, where routes just overlap without penalty.
476 --------------------------------------------------------------------------------------------------*/
initialSolution(dvSchema schema)477 static void initialSolution(
478 dvSchema schema)
479 {
480 dvRelationship relationship;
481
482
483 dvForeachSchemaRelationship(schema, relationship) {
484 routeRelationship(relationship);
485 } dvEndSchemaRelationship;
486 }
487
488 /*--------------------------------------------------------------------------------------------------
489 Rip a route
490 --------------------------------------------------------------------------------------------------*/
dwRipRoute(dwRoute route)491 static void dwRipRoute(
492 dwRoute route)
493 {
494 dwBund bund = dwRouteGetBund(route);
495 dwRoute firstRoute;
496
497 dwRouteDestroy(route);
498 firstRoute = dwBundGetFirstRoute(bund);
499 if(firstRoute != dwRouteNull) {
500 dwOverconstraints--;
501 }
502 }
503
504 /*--------------------------------------------------------------------------------------------------
505 Randomize the relationships order
506 --------------------------------------------------------------------------------------------------*/
randomizeRelationships()507 static void randomizeRelationships()
508 {
509 dvRelationship relationship1, relationship2;
510 uint32 temp1, temp2;
511 uint32 numRelationships = dwRelationshipArrayGetUsedRelationship(dwRandRelationships);
512
513 for(temp1 = 0; temp1 < numRelationships; temp1++) {
514 temp2 = temp1 + utRandN(numRelationships - temp1);
515 relationship1 = dwRelationshipArrayGetiRelationship(dwRandRelationships, temp1);
516 relationship2 = dwRelationshipArrayGetiRelationship(dwRandRelationships, temp2);
517 dwRelationshipArraySetiRelationship(dwRandRelationships, temp1, relationship2);
518 dwRelationshipArraySetiRelationship(dwRandRelationships, temp2, relationship1);
519 }
520 }
521
522 /*--------------------------------------------------------------------------------------------------
523 Rip all routes of a bundle
524 --------------------------------------------------------------------------------------------------*/
dwRipRelationshipRoutes(dvRelationship relationship)525 static void dwRipRelationshipRoutes(
526 dvRelationship relationship)
527 {
528 dwRoute route;
529
530 dwSafeForeachRelationshipRoute(relationship, route) {
531 dwRipRoute(route);
532 } dwEndSafeRelationshipRoute;
533 }
534
535 /*--------------------------------------------------------------------------------------------------
536 Rip-up and reroute at least a few times to improve readability, or continue until DRCs are gone
537 or we give up.
538 --------------------------------------------------------------------------------------------------*/
fillRelationshipArray(dvSchema schema)539 static void fillRelationshipArray(
540 dvSchema schema)
541 {
542 dvRelationship relationship;
543
544 dvForeachSchemaRelationship(schema, relationship) {
545 dwRelationshipArrayAppendRelationship(dwRandRelationships, relationship);
546 } dvEndSchemaRelationship;
547
548 }
549
550 /*--------------------------------------------------------------------------------------------------
551 Rip-up and reroute at least a few times to improve readability, or continue until DRCs are gone
552 or we give up.
553 --------------------------------------------------------------------------------------------------*/
ripUpandReroute(dvSchema schema)554 static void ripUpandReroute(
555 dvSchema schema)
556 {
557 dvRelationship relationship;
558
559 randomizeRelationships(); /*zxcbreak*/
560 dwForeachRelationshipArrayRelationship(dwRandRelationships, relationship) { /*zxcbreak*/
561 dwRipRelationshipRoutes(relationship); /*zxcbreak*/
562 routeRelationship(relationship); /*zxcbreak*/
563 } dwEndRelationshipArrayRelationship;
564 }
565
566 /*--------------------------------------------------------------------------------------------------
567 Route Until Completion
568 --------------------------------------------------------------------------------------------------*/
routeUntilComplete(dvSchema schema)569 static void routeUntilComplete(
570 dvSchema schema)
571 {
572 uint32 dwCycle = 0;
573
574 fillRelationshipArray(schema); /*zxcbreak*/
575 do{
576 utIfDebug(1) {
577 utLogDebug("cycles = %d overconstraints = %d", dwCycle, dwOverconstraints);
578 }
579 dwOverconstraintPenalty++;
580 ripUpandReroute(schema);
581 dwCycle++;
582 } while((dwCycle < 10 || dwOverconstraints != 0) && dwCycle < 100);
583 }
584
585 /*--------------------------------------------------------------------------------------------------
586 Route relationships on the schema. Return the number of DRCs.
587 --------------------------------------------------------------------------------------------------*/
dwRouteSchema(dvSchema schema)588 uint32 dwRouteSchema(
589 dvSchema schema)
590 {
591 dwRandRelationships = dwRelationshipArrayAlloc();
592 dwBucketFreeAll();
593 dwBundFreeAll();
594 dwAdjFreeAll(); /*zxcbreak*/
595 dwRandBunds = dwBundArrayAlloc();
596 buildRoutingGraph(schema);
597 addClassesToGraph(schema);
598 dwOverconstraints = 0;
599 dwOverconstraintPenalty = 0;
600 initialSolution(schema);
601 routeUntilComplete(schema);
602 dwBundArrayFree(dwRandBunds);
603 dwRelationshipArrayFree(dwRandRelationships);
604 return dwOverconstraints;
605 }
606