/* * grouteMulti.c * * Route a multi-terminal net. * Currently includes just a single algorithm, for routing a net * where arbitrary branching is allowed. This algorithm produces * something like a steiner-tree, with intermediate points introduced * at channel boundaries. * * ********************************************************************* * * Copyright (C) 1985, 1990 Regents of the University of California. * * * Permission to use, copy, modify, and distribute this * * * software and its documentation for any purpose and without * * * fee is hereby granted, provided that the above copyright * * * notice appear in all copies. The University of California * * * makes no representations about the suitability of this * * * software for any purpose. It is provided "as is" without * * * express or implied warranty. Export of this software outside * * * of the United States of America may require an export license. * * ********************************************************************* */ #ifndef lint static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/grouter/grouteMult.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $"; #endif /* lint */ #include #include "utils/magic.h" #include "utils/geometry.h" #include "utils/hash.h" #include "utils/heap.h" #include "tiles/tile.h" #include "database/database.h" #include "router/router.h" #include "gcr/gcr.h" #include "grouter/grouter.h" #include "utils/netlist.h" #include "utils/signals.h" #include "textio/textio.h" #include "utils/malloc.h" #include "utils/styles.h" #include "windows/windows.h" #include "dbwind/dbwind.h" /* Forward declarations */ void glMultiAddStart(); /* * ---------------------------------------------------------------------------- * * glMultiSteiner -- * * Perform global routing for all segments of a net. * The caller supplies two procedures: one to produce a list of * GlPoints from any of a set of possible starting points to the * single destination, and the other to accept a list of GlPoints * and remember it permanently, e.g, in the form of crossing assignments. * * The two procedures are of the following form: * * GlPoint * * (*routeProc)(startList, loc, bestCost, cdRoute) * GlPoint *startList; --- list of GlPoints that are possible * --- starting points for the route; the * --- points in the list are linked via gl_path * --- fields as though they were a path. * NLTermLoc *loc; --- loc->nloc_pin is the destination * int bestCost; --- return NULL if we can't beat this cost * ClientData cdRoute; --- same as cdRoute passed to us * { * } * * int * (*markProc)(rootUse, path, pNetId, cdMark) * CellUse *rootUse; --- leave feedback here if necessary and if * --- rootUse is non-NULL * GlPoint *path; --- path to be marked * NetId *pNetId; --- netid_net is the argument 'net' to * --- glMultiSteiner; netid_seg will be * --- incremented for each new segment id * --- assigned. * ClientData cdMark; --- same as 'cdMark' passed to us * { * } * * * Assumptions: * The net has at least two terminals, each of which has at least * one valid location. * * Algorithm: * Multiterminal nets are routed using an algorithm that finds * pseudo-Steiner tree routes. The idea is to process the * terminals of the net in the order they appear in the netlist. * Processing consists of finding the shortest path from the * terminal being considered to all of the terminals processed * before it, or to any of the crossing points used by the routes * used to connect these previously-processed terminals. * * Results: * Returns the number of terminals processed. * * Side effects: * Whatever (*routeProc)() and (*markProc)() do. * * ---------------------------------------------------------------------------- */ int glMultiSteiner(rootUse, net, routeProc, markProc, cdRoute, cdMark) CellUse *rootUse; /* If non-NULL, feedback for errors left here */ NLNet *net; /* Net to process */ GlPoint *(*routeProc)(); /* Procedure to route a segment */ int (*markProc)(); /* Procedure to remember the route */ ClientData cdRoute; /* Passed to (*routeProc)() */ ClientData cdMark; /* Passed to (*markProc)() */ { GlPoint *startList, *bestDest, *dest; char mesg[128], *lastTermName; int bestCost, nterms; NLTermLoc *loc; NLTerm *term; Rect errorArea; NetId netid; /* Skip to the first term that has a location */ ASSERT(net != (NLNet *) NULL, "glMultiSteiner"); for (term = net->nnet_terms; term; term = term->nterm_next) if (term->nterm_locs) break; ASSERT(term != (NLTerm *) NULL, "glMultiSteiner"); /* * For the first terminal in the net, mark the point where the terminal * enters its adjacent channel. If there are several electrically * equivalent terminals, then mark them all. */ nterms = 0; startList = (GlPoint *) NULL; lastTermName = term->nterm_name; for (loc = term->nterm_locs; loc; loc = loc->nloc_next) glListAdd(&startList, loc->nloc_pin, glMultiStemCost(loc)); /* Process all other terminals in net */ netid.netid_net = net; netid.netid_seg = 1; for (term = term->nterm_next; term; term = term->nterm_next) { /* * Skip if no valid locations exist for this terminal; * the error has already been reported (either in the * stem generator or the netlist reader). */ if (term->nterm_locs == (NLTermLoc *) NULL) continue; /* * Consider routing to each of the possible locations for * this terminal, and use the best path. (The comparison of * route cost includes the final channel in each path). * After each call to rgRoutePath, 'dest' will be a GlPoint * for one of the zero-cost points to 'loc' (or NULL if no * path could be found). */ bestCost = INFINITY; bestDest = (GlPoint *) NULL; for (loc = term->nterm_locs; loc; loc = loc->nloc_next) { nterms++; /* Try to find a path from a zero-cost point to loc */ dest = (*routeProc)(startList, loc, bestCost, cdRoute); /* Remember it if it was better than the previous best */ if (dest && dest->gl_cost < bestCost) { if (bestDest) glPathFreePerm(bestDest); bestDest = glPathCopyPerm(dest); bestCost = dest->gl_cost; } /* Free all temporary storage used for GlPoints */ glPathFreeTemp(); } /* * If we were successful in finding a path, add the crossing points * to the zero-cost list, mark all the crossings it used as allocated, * and update the segment-id. */ if (bestDest) { glMultiAddStart(bestDest, &startList); (*markProc)(rootUse, bestDest, &netid, cdMark); glPathFreePerm(bestDest); /* * Finally, move all of the locations for the terminal just * processed to the zero-cost list, since any of them can * be used as a new starting point. */ for (loc = term->nterm_locs; loc; loc = loc->nloc_next) glListAdd(&startList, loc->nloc_pin, glMultiStemCost(loc)); lastTermName = term->nterm_name; } else { GEO_EXPAND(&term->nterm_locs->nloc_rect, 1, &errorArea); sprintf(mesg, "Can't find a path from \"%s\" to \"%s\"", term->nterm_name, lastTermName); if (rootUse) DBWFeedbackAdd(&errorArea, mesg, rootUse->cu_def, 1, STYLE_PALEHIGHLIGHTS); else TxError("%s\n", mesg); } } /* Free the list of starting points */ glPathFreePerm(startList); return nterms; } /* * ---------------------------------------------------------------------------- * * glMultiStemCost -- * * Compute the initial cost of a terminal. This is the cost from the * terminal loc->nloc_rect to its initial crossing point loc->nloc_stem. * * Results: * Returns the Manhattan distance just described. * * Side effects: * None. * * ---------------------------------------------------------------------------- */ int glMultiStemCost(loc) NLTermLoc *loc; { int n1, n2, cost; n1 = ABSDIFF(loc->nloc_stem.p_x, loc->nloc_rect.r_xbot); n2 = ABSDIFF(loc->nloc_stem.p_x, loc->nloc_rect.r_xtop); cost = MIN(n1, n2); n1 = ABSDIFF(loc->nloc_stem.p_y, loc->nloc_rect.r_ybot); n2 = ABSDIFF(loc->nloc_stem.p_y, loc->nloc_rect.r_ytop); cost += MIN(n1, n2); return cost; } /* * ---------------------------------------------------------------------------- * * glMultiAddStart -- * * Add all the pins along the GlPoint 'path' to the list of * starting points '*pStartList'. For each crossing we add * up to two pins: one on each side of the crossing. * If a pin has already been marked as belonging to * a net, we don't add it, since it was already added * in an earlier iteration. * * Results: * None. * * Side effects: * Prepends the GlPoints on the list 'path' to the list of * starting points *pStart. * * ---------------------------------------------------------------------------- */ void glMultiAddStart(path, pStartList) GlPoint *path; /* Path linked via gl_path pointers */ GlPoint **pStartList; /* List of starting points */ { GlPoint *srcEntry, *dstEntry; GCRPin *srcPin, *dstPin; /* * Walk from path back along gl_path pointers down the list. * At each step, process the segment between srcEntry and * dstEntry in the channel srcEntry->gl_pin->gcr_ch. */ for (srcEntry = path->gl_path, dstEntry = path; srcEntry; dstEntry = srcEntry, srcEntry = srcEntry->gl_path) { /* Use srcPin's channel for both srcPin and dstPin */ srcPin = srcEntry->gl_pin; dstPin = dstEntry->gl_pin; if (dstPin->gcr_ch != srcPin->gcr_ch) dstPin = dstPin->gcr_linked; ASSERT(dstPin && dstPin->gcr_ch == srcPin->gcr_ch, "glMultiAddStart"); /* Add to list of starting points */ if (srcPin->gcr_pId == NULL || srcPin->gcr_pSeg == GCR_STEMSEGID) glListAdd(pStartList, srcPin, 0); glListAdd(pStartList, dstPin, 0); } }