911 lines
25 KiB
C
911 lines
25 KiB
C
/*
|
|
* groutePen.c
|
|
*
|
|
* Computation of the penalties to be assigned for each net using
|
|
* certain congested regions.
|
|
*
|
|
* *********************************************************************
|
|
* * 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/groutePen.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
|
#endif /* lint */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h> /* For qsort() */
|
|
#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 "utils/netlist.h"
|
|
#include "gcr/gcr.h"
|
|
#include "router/router.h"
|
|
#include "grouter/grouter.h"
|
|
#include "utils/signals.h"
|
|
#include "textio/textio.h"
|
|
#include "utils/malloc.h"
|
|
#include "utils/styles.h"
|
|
#include "utils/list.h"
|
|
|
|
/* Forward declarations */
|
|
void glPenSavePath();
|
|
int glPenSortNetSet();
|
|
int glPenFindCrossingFunc();
|
|
int glPenDeleteFunc();
|
|
int glPenRouteCost();
|
|
int glPenRerouteNetCost();
|
|
NetSet *glPenFindCrossingNets();
|
|
CZone *glPenScanDens();
|
|
CZone *glPenFindCZones();
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glPenSetPerChan --
|
|
* glPenClearPerChan --
|
|
*
|
|
* Visit all of the channels on the CZone list for 'net'
|
|
* (this list is ((NetClient *) net->nnet_cdata)->nc_pens);
|
|
* glPenSetPerChan will prepend a copy of each CZone
|
|
* to the penalty list for the appropriate channel, while
|
|
* glPenClearPerChan will free the list for each channel.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* See above.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
glPenSetPerChan(net)
|
|
NLNet *net;
|
|
{
|
|
CZone *czNet, *czChan;
|
|
GlobChan *gc;
|
|
|
|
for (czNet = ((NetClient *) net->nnet_cdata)->nc_pens;
|
|
czNet;
|
|
czNet = czNet->cz_next)
|
|
{
|
|
gc = (GlobChan *) czNet->cz_chan->gcr_client;
|
|
czChan = (CZone *) mallocMagic((unsigned) (sizeof (CZone)));
|
|
*czChan = *czNet;
|
|
czChan->cz_next = gc->gc_penList;
|
|
gc->gc_penList = czChan;
|
|
}
|
|
}
|
|
|
|
int
|
|
glPenClearPerChan(net)
|
|
NLNet *net;
|
|
{
|
|
CZone *czNet, *czChan;
|
|
GlobChan *gc;
|
|
|
|
for (czNet = ((NetClient *) net->nnet_cdata)->nc_pens;
|
|
czNet;
|
|
czNet = czNet->cz_next)
|
|
{
|
|
gc = (GlobChan *) czNet->cz_chan->gcr_client;
|
|
for (czChan = gc->gc_penList; czChan; czChan = czChan->cz_next)
|
|
freeMagic((char *) czChan);
|
|
gc->gc_penList = (CZone *) NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glPenCompute --
|
|
*
|
|
* Some routing regions will have many nets passing through them.
|
|
* It may be, however, that some of these nets need a given region
|
|
* much more than others: the cost to them of going around the
|
|
* region is very high. This procedure attempts to identify
|
|
* congested regions (CZones), and furthermore to determine the
|
|
* nets that should be penalized for using those regions and the
|
|
* amount of the penalty.
|
|
*
|
|
* On input, the gc_prevDens and gc_postDens fields of each channel's
|
|
* associated GlobChan structure should be set up to reflect the
|
|
* presence of blocking information.
|
|
*
|
|
* Algorithm:
|
|
* Route each net as though it were the first net to be routed.
|
|
* Avoid routing through any portion of a channel that is already
|
|
* at density (from pre-existing wiring), but otherwise don't
|
|
* bother computing penalties. Choose crossing points to give
|
|
* locally (i.e, per-channel) optimal lengths. This enables
|
|
* us to avoid looking at most crossing points so we can route
|
|
* very quickly.
|
|
*
|
|
* Remember each of the paths that comprised each net by storing
|
|
* a permanent copy of each in the list nc_paths in the NetClient
|
|
* structure for each net.
|
|
*
|
|
* After all nets have been processed, update density in the
|
|
* gc_postDens density map of all channels to reflect the routes
|
|
* assigned to all nets. For each region of a channel where density
|
|
* has been exceeded, we look at all the nets that pass through the
|
|
* region and see how expensive it would be to route each one if it
|
|
* had to avoid that region entirely. (It is infinitely expensive
|
|
* if the region contains either the starting or ending point of the
|
|
* route!)
|
|
*
|
|
* While the costs computed above are just an estimate (since they
|
|
* consider each net independently), the hope is that they will
|
|
* identify fairly well those nets that can easily avoid congested
|
|
* areas with only slight detours, as well as those nets for which
|
|
* certain regions of channels are critical.
|
|
*
|
|
* We pick those nets whose cost increases the least by having to
|
|
* avoid the congested region as those that will be penalized; the
|
|
* penalty for each net is the additional cost of avoiding the region
|
|
* for the net for which this cost is highest. (In effect, this gives
|
|
* us a balanced tradeoff: the net with low cost for not using the
|
|
* channel won't use it unless it has otherwise to make at least as
|
|
* big a detour as our estimate for the most expensive one).
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Stores a pointer to a list of CZone structures in
|
|
* the nnet_cdata->nc_pens field of each net in netList.
|
|
* (The list may be NULL). Each element in the list identifies
|
|
* a channel and a penalty; the interpretation is that this
|
|
* net should be penalized by the indicated penalty if it
|
|
* has to go through this channel.
|
|
* Also uses nnet_cdata->nc_paths as temporary working storage.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
glPenCompute(chanList, netList)
|
|
GCRChannel *chanList; /* All the channels in the routing problem */
|
|
NLNetList *netList; /* Netlist being routed */
|
|
{
|
|
#ifdef notdef
|
|
CZone *czones, *cz;
|
|
GlobChan *gc;
|
|
GCRChannel *ch;
|
|
NLNet *net;
|
|
|
|
/*
|
|
* Process nets in the order they appear, since this routing
|
|
* is order-independent. After all done, we have remembered
|
|
* the GlPoints for all a net's segments in the NetClient nc_paths
|
|
* list for that net. Also, the density map gc_postDens in each
|
|
* channel's GlobChan has been set.
|
|
*/
|
|
for (net = netList->nnl_nets; net; net = net->nnet_next)
|
|
glMultiSteiner((CellUse *) NULL, net, glProcessLoc, glPenSavePath,
|
|
(ClientData) TRUE, (ClientData) NULL);
|
|
|
|
/*
|
|
* Set the density map gc_postDens in all channels.
|
|
* The initial contents of gc_postDens should have been set
|
|
* to the same as gc_prevDens by the caller; we just add
|
|
* all the nets routed in the step above.
|
|
*/
|
|
for (net = netList->nnl_nets; net; net = net->nnet_next)
|
|
glPenDensitySet(net);
|
|
|
|
/*
|
|
* Find all the congested zones in the circuit and store them in
|
|
* a list of CZone structures.
|
|
*/
|
|
czones = glPenFindCZones(chanList);
|
|
|
|
/*
|
|
* Process each CZone to determine which nets should be assigned
|
|
* penalties for crossing that zone. The penalties assigned to
|
|
* a net for a CZone in an earlier iteration apply to attempts
|
|
* to route that net around other CZones in later iterations.
|
|
* The final result of this step is to build the nc_pens list
|
|
* for each net's NetClient structure.
|
|
*/
|
|
for (cz = czones; cz; cz = cz->cz_next)
|
|
glPenAssignCosts(cz, netList);
|
|
|
|
/*
|
|
* Final cleanup: free the GlPoints in each net's nc_paths list,
|
|
* since they're no longer needed. Also reset gc_postDens in
|
|
* each channel to its initial value, gc_prevDens.
|
|
*/
|
|
for (net = netList->nnl_nets; net; net = net->nnet_next)
|
|
glPenCleanNet(net);
|
|
for (ch = chanList; ch; ch = ch->gcr_next)
|
|
{
|
|
gc = (GlobChan *) ch->gcr_client;
|
|
glDMCopy(&gc->gc_prevDens[CZ_COL], &gc->gc_postDens[CZ_COL]);
|
|
glDMCopy(&gc->gc_prevDens[CZ_ROW], &gc->gc_postDens[CZ_ROW]);
|
|
}
|
|
#endif /* notdef */
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glPenFindCZones --
|
|
*
|
|
* Build up a list of all congested zones in all channels.
|
|
* See grouter.h for a definition of a congested zone.
|
|
* The density map we search is gc_postDens.
|
|
*
|
|
* Results:
|
|
* Returns a pointer to the list.
|
|
*
|
|
* Side effects:
|
|
* Allocates memory.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
CZone *
|
|
glPenFindCZones(chanList)
|
|
GCRChannel *chanList; /* All the channels in the routing problem */
|
|
{
|
|
CZone *czList;
|
|
DensMap *dmap;
|
|
GCRChannel *ch;
|
|
|
|
czList = (CZone *) NULL;
|
|
for (ch = chanList; ch; ch = ch->gcr_next)
|
|
{
|
|
dmap = ((GlobChan *) ch->gcr_client)->gc_postDens;
|
|
czList = glPenScanDens(czList, ch, &dmap[CZ_COL], CZ_COL);
|
|
czList = glPenScanDens(czList, ch, &dmap[CZ_ROW], CZ_ROW);
|
|
}
|
|
|
|
return czList;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glPenScanDens --
|
|
*
|
|
* Scan for portions of a density map where the density exceeds the
|
|
* capacity, and allocate a CZone for each such range.
|
|
*
|
|
* Results:
|
|
* Returns a pointer to a CZone list with the new elements
|
|
* described above prepended to czList.
|
|
*
|
|
* Side effects:
|
|
* Allocates memory.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
CZone *
|
|
glPenScanDens(czList, ch, dm, type)
|
|
CZone *czList; /* Prepend to this list */
|
|
GCRChannel *ch; /* Which channel is being processed */
|
|
DensMap *dm; /* Map to search */
|
|
int type; /* Type of zone: CZ_ROW or CZ_COL */
|
|
{
|
|
short *val = dm->dm_value;
|
|
CZone *cz;
|
|
int i;
|
|
|
|
/* Nothing to do if the capacity is never exceeded */
|
|
if (dm->dm_max <= dm->dm_cap)
|
|
return czList;
|
|
|
|
/*
|
|
* Simple state machine to find the start and end of
|
|
* each zone of excess density. If cz is NULL then
|
|
* we're currently out of a zone; otherwise, we're
|
|
* building one up. Consider elements of the density
|
|
* map from 1 .. dm->dm_size.
|
|
*/
|
|
cz = (CZone *) NULL;
|
|
for (i = 1; i < dm->dm_size; i++)
|
|
{
|
|
if (cz)
|
|
{
|
|
if (val[i] <= dm->dm_cap)
|
|
{
|
|
/* End of congested zone */
|
|
cz->cz_hi = i - 1;
|
|
cz = (CZone *) NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (val[i] > dm->dm_cap)
|
|
{
|
|
/* Beginning of congested zone */
|
|
cz = (CZone *) mallocMagic((unsigned) (sizeof (CZone)));
|
|
cz->cz_chan = ch;
|
|
cz->cz_type = type;
|
|
cz->cz_lo = i;
|
|
cz->cz_penalty = 0;
|
|
cz->cz_nets = (NetSet *) NULL;
|
|
cz->cz_next = czList;
|
|
czList = cz;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Take care of case when a CZone extends all the way to the end */
|
|
if (cz) cz->cz_hi = dm->dm_size - 1;
|
|
|
|
return czList;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glPenAssignCosts --
|
|
*
|
|
* Find all nets that cross a congested zone and determine how expensive
|
|
* it would be to reroute each if they had to avoid that zone. Once this
|
|
* cost is determined for all nets affected, pick the N least-cost nets,
|
|
* where N is the number of nets that would have to be re-routed in order
|
|
* to reduce the number running through the congested zone to be within
|
|
* its capacity (N should always be greater than zero). Prepend a CZone
|
|
* to the np_pens list of each of these N nets NetClients, with a cz_penalty
|
|
* equal to the cost of the most-expensive-to-reroute net.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Allocates memory for the CZones placed on each NetClient's np_pens
|
|
* list; see above for details.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
glPenAssignCosts(cz, netList)
|
|
CZone *cz; /* A single CZone being processed */
|
|
NLNetList *netList; /* List of all nets; we look for nets that cross
|
|
* this zone.
|
|
*/
|
|
{
|
|
int oldCost, newCost, maxCost, numCross, density;
|
|
NetSet *crossNets, *ns, **crossArray, **nsap;
|
|
GlobChan *gc;
|
|
DensMap *dm;
|
|
CZone *czNew;
|
|
NetClient *nc;
|
|
List *list;
|
|
|
|
/* Find the nets that use this congested zone */
|
|
crossNets = glPenFindCrossingNets(cz, netList);
|
|
|
|
/*
|
|
* For each net in the set, determine how expensive it would be
|
|
* if it couldn't use this congested zone at all.
|
|
*/
|
|
maxCost = 0;
|
|
numCross = 0;
|
|
for (ns = crossNets; ns; ns = ns->ns_next)
|
|
{
|
|
oldCost = 0;
|
|
nc = (NetClient *) ns->ns_net->nnet_cdata;
|
|
|
|
for (list = nc->nc_paths; list; list = LIST_TAIL(list))
|
|
oldCost += ((GlPoint *) LIST_FIRST(list))->gl_cost;
|
|
newCost = glPenRerouteNetCost(cz, ns->ns_net);
|
|
ns->ns_cost = newCost - oldCost;
|
|
if (ns->ns_cost > maxCost) maxCost = ns->ns_cost;
|
|
numCross++;
|
|
}
|
|
|
|
/*
|
|
* Sort the NetSets on the crossNets list in order of increasing
|
|
* ns_cost, leaving crossArray[i] pointing to the i'th smallest
|
|
* NetSet.
|
|
*/
|
|
crossArray = (NetSet **) mallocMagic((unsigned) (numCross * sizeof (NetSet *)));
|
|
for (ns = crossNets, nsap = crossArray; ns; ns = ns->ns_next) *nsap++ = ns;
|
|
qsort(crossArray, numCross, sizeof (NetSet *), glPenSortNetSet);
|
|
|
|
/*
|
|
* Now comes the fun part.
|
|
* We must select a group of nets to assign a penalty of maxCost.
|
|
* The best nets to receive this penalty are those whose cost
|
|
* to reroute around 'cz' is least. However, we also want to
|
|
* assign this penalty to the minimum number of nets necessary
|
|
* to eliminate the congestion at 'cz' (i.e, to reduce the
|
|
* density to equal the channel capacity).
|
|
*
|
|
* The approach below is to start pulling nets out of the
|
|
* congested zone, in order of increasing ns_cost, until
|
|
* the congestion disappears.
|
|
*/
|
|
gc = (GlobChan *) cz->cz_chan->gcr_client;
|
|
dm = &gc->gc_postDens[cz->cz_type];
|
|
density = glDMMaxInRange(dm, cz->cz_lo, cz->cz_hi);
|
|
nsap = crossArray;
|
|
while (density > dm->dm_cap)
|
|
{
|
|
ns = *nsap++;
|
|
nc = (NetClient *) ns->ns_net->nnet_cdata;
|
|
czNew = (CZone *) mallocMagic((unsigned) (sizeof (CZone)));
|
|
*czNew = *cz;
|
|
czNew->cz_penalty = maxCost;
|
|
czNew->cz_nets = (NetSet *) NULL;
|
|
czNew->cz_next = nc->nc_pens;
|
|
nc->nc_pens = czNew;
|
|
|
|
/* Update 'dm' to reflect the absence of the net */
|
|
density = glPenDeleteNet(dm, nc->nc_paths, cz);
|
|
}
|
|
|
|
/* Cleanup */
|
|
for (ns = crossNets; ns; ns = ns->ns_next)
|
|
freeMagic((char *) ns);
|
|
freeMagic((char *) crossArray);
|
|
}
|
|
|
|
/*
|
|
* glPenSortNetSet --
|
|
*
|
|
* Called by qsort() to compare the ns_cost values of two NetSets
|
|
* pointed to by *ns1 and *ns2 respectively.
|
|
*
|
|
* Results:
|
|
* (*ns1)->ns_cost ? (*ns2)->ns_cost returns
|
|
* --------------------------------- -------
|
|
* > 1
|
|
* < -1
|
|
* = 0
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*/
|
|
|
|
int
|
|
glPenSortNetSet(ns1, ns2)
|
|
NetSet **ns1, **ns2;
|
|
{
|
|
if ((*ns1)->ns_cost > (*ns2)->ns_cost) return 1;
|
|
if ((*ns1)->ns_cost < (*ns2)->ns_cost) return -1;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glPenFindCrossingNets --
|
|
*
|
|
* Find all the nets in 'netList' whose routes cross through the
|
|
* congested zone 'cz'.
|
|
*
|
|
* Results:
|
|
* Returns a list of NetSet structs pointing to the nets
|
|
* found to cross through 'cz'.
|
|
*
|
|
* Side effects:
|
|
* Allocates memory.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/* Structure passed to glPenFindCrossingFunc() via glPenEnumCross() */
|
|
struct glCrossClient
|
|
{
|
|
NLNet *rcc_net; /* Net whose segments are being enumerated */
|
|
NetSet *rcc_set; /* NetSet being built up */
|
|
};
|
|
|
|
NetSet *
|
|
glPenFindCrossingNets(cz, netList)
|
|
CZone *cz; /* A single CZone being processed */
|
|
NLNetList *netList; /* List of all nets; we look for nets that cross
|
|
* this zone.
|
|
*/
|
|
{
|
|
struct glCrossClient rcc;
|
|
List *list;
|
|
NLNet *net;
|
|
|
|
rcc.rcc_set = (NetSet *) NULL;
|
|
for (net = netList->nnl_nets; net; net = net->nnet_next)
|
|
{
|
|
rcc.rcc_net = net;
|
|
for (list = ((NetClient *) net->nnet_cdata)->nc_paths;
|
|
list;
|
|
list = LIST_TAIL(list))
|
|
{
|
|
if (glPenEnumCross(cz, (GlPoint *) LIST_FIRST(list),
|
|
glPenFindCrossingFunc, (ClientData) &rcc))
|
|
break;
|
|
}
|
|
}
|
|
|
|
return rcc.rcc_set;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glPenFindCrossingFunc --
|
|
*
|
|
* Filter function for glPenFindCrossingNets() above, called by
|
|
* glPenEnumCross() for each segment on an GlPoint that crosses
|
|
* through the CZone 'cz'.
|
|
*
|
|
* Results:
|
|
* Always returns 1.
|
|
*
|
|
* Side effects:
|
|
* Allocates a NetSet for rcc->rcc_net and prepends it
|
|
* to the NetSet list rcc->rcc_set.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*ARGSUSED*/
|
|
int
|
|
glPenFindCrossingFunc(cz, srcPin, dstPin, rcc)
|
|
CZone *cz; /* UNUSED */
|
|
GCRPin *srcPin, *dstPin; /* UNUSED */
|
|
struct glCrossClient *rcc;
|
|
{
|
|
NetSet *ns;
|
|
|
|
ns = (NetSet *) mallocMagic((unsigned) (sizeof (NetSet)));
|
|
ns->ns_net = rcc->rcc_net;
|
|
ns->ns_cost = 0;
|
|
ns->ns_next = rcc->rcc_set;
|
|
rcc->rcc_set = ns;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glPenEnumCross --
|
|
*
|
|
* Find all the segments on the GlPoint 'rp' that pass through the CZone 'cz'.
|
|
* For each segment, call the supplied procedure (*func)(), which should be
|
|
* of the following form:
|
|
*
|
|
* int
|
|
* (*func)(cz, srcPin, dstPin, cdata)
|
|
* CZone *cz; --- same as our argument 'cz'
|
|
* GCRPin *srcPin, *dstPin; --- two pins in cz's channel
|
|
* ClientData cdata; --- same as our argument 'cdata'
|
|
* {
|
|
* }
|
|
*
|
|
* This procedure should return 0 if glPenEnumCross() is to continue
|
|
* visiting further segments of the GlPoint, or a non-zero value if
|
|
* we are to stop visiting further segments.
|
|
*
|
|
* Results:
|
|
* Returns 0 if the end of the GlPoint was reached without
|
|
* (*func)() returning a non-zero value (or if no segments
|
|
* crossed through 'cz'). Returns 1 if (*func)() returned
|
|
* a non-zero value for some segment.
|
|
*
|
|
* Side effects:
|
|
* Whatever (*func)() does.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
glPenEnumCross(cz, rp, func, cdata)
|
|
CZone *cz; /* Look for segments passing through here */
|
|
GlPoint *rp; /* List of GlPoints (linked by gl_path ptrs) */
|
|
int (*func)(); /* Apply to each segment passing through cz */
|
|
ClientData cdata; /* Passed to (*func)() */
|
|
{
|
|
GCRPin *srcPin, *dstPin;
|
|
int cSrc, cDst;
|
|
|
|
for ( ; rp->gl_path; rp = rp->gl_path)
|
|
{
|
|
/* Only interested if this segment is in cz_chan */
|
|
srcPin = rp->gl_path->gl_pin;
|
|
if (srcPin->gcr_ch != cz->cz_chan)
|
|
continue;
|
|
dstPin = rp->gl_pin;
|
|
if (dstPin->gcr_ch != srcPin->gcr_ch)
|
|
dstPin = dstPin->gcr_linked;
|
|
|
|
if (cz->cz_type == CZ_ROW)
|
|
{
|
|
cSrc = srcPin->gcr_y;
|
|
cDst = dstPin->gcr_y;
|
|
}
|
|
else
|
|
{
|
|
cSrc = srcPin->gcr_x;
|
|
cDst = dstPin->gcr_x;
|
|
}
|
|
|
|
if ((cSrc >= cz->cz_lo && cSrc <= cz->cz_hi)
|
|
|| (cDst >= cz->cz_lo && cDst <= cz->cz_hi))
|
|
{
|
|
if ((*func)(cz, srcPin, dstPin, cdata))
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glPenRerouteNetCost --
|
|
*
|
|
* Determine how expensive it would be for net 'net' if it couldn't
|
|
* be routed through 'cz'.
|
|
*
|
|
* Results:
|
|
* Cost value.
|
|
*
|
|
* Side effects:
|
|
* Frees memory; resets the nc_paths list to NULL.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
glPenRerouteNetCost(cz, net)
|
|
CZone *cz;
|
|
NLNet *net; /* Net to be rerouted */
|
|
{
|
|
NetClient *nc = (NetClient *) net->nnet_cdata;
|
|
CZone fakeCZ;
|
|
int cost;
|
|
|
|
/* Prepend a fake CZone with infinite cost */
|
|
fakeCZ = *cz;
|
|
fakeCZ.cz_penalty = INFINITY;
|
|
fakeCZ.cz_next = nc->nc_pens;
|
|
nc->nc_pens = &fakeCZ;
|
|
|
|
/*
|
|
* Set the channel penalties and perform a normal routing,
|
|
* but just sum the cost of the resultant path instead of
|
|
* storing it anywhere.
|
|
*/
|
|
cost = 0;
|
|
glPenSetPerChan(net);
|
|
glMultiSteiner((CellUse *) NULL, net, glProcessLoc, glPenRouteCost,
|
|
(ClientData) TRUE, (ClientData) &cost);
|
|
glPenClearPerChan(net);
|
|
|
|
/* Remove the fake CZone */
|
|
nc->nc_pens = nc->nc_pens->cz_next;
|
|
|
|
return cost;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
int
|
|
glPenRouteCost(rootUse, bestPath, pNetId, pCost)
|
|
CellUse *rootUse; /* UNUSED */
|
|
GlPoint *bestPath; /* Best path for this segment */
|
|
NetId *pNetId; /* UNUSED */
|
|
int *pCost; /* Add bestPath->gl_cost to this */
|
|
{
|
|
*pCost += bestPath->gl_cost;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glPenDeleteNet --
|
|
*
|
|
* Modify the density map 'dm' to reflect the absence of all
|
|
* segments on 'list' (a List each of whose elements is the first
|
|
* GlPoints on a path of GlPoints) that pass through the CZone 'cz'.
|
|
* Only the entries of the density map that lie between cz->cz_lo
|
|
* and cz->cz_hi (inclusive) are affected.
|
|
*
|
|
* Results:
|
|
* Returns the new maximum density in 'dm' in the range
|
|
* cz->cz_lo through cz->cz_hi inclusive.
|
|
*
|
|
* Side effects:
|
|
* Modifies 'dm' as described above.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
glPenDeleteNet(dm, list, cz)
|
|
DensMap *dm; /* Update this map */
|
|
List *list; /* List of paths */
|
|
CZone *cz; /* Remove all segments passing through 'cz' from 'dm' */
|
|
{
|
|
for ( ; list; list = LIST_TAIL(list))
|
|
(void) glPenEnumCross(cz, (GlPoint *) LIST_FIRST(list),
|
|
glPenDeleteFunc, (ClientData) dm);
|
|
|
|
return glDMMaxInRange(dm, cz->cz_lo, cz->cz_hi);
|
|
}
|
|
|
|
/*
|
|
* glPenDeleteFunc --
|
|
*
|
|
* Do the real work of glPenDeleteNet() above. Called by glPenEnumCross()
|
|
* for each segment of the global routing of a net that passes through 'cz'.
|
|
* Updates 'dm' to reflect the ripping up of that portion of the segment
|
|
* that actually passes through 'cz'; portions of 'dm' that lie outside
|
|
* of 'cz' (cz->cz_lo through cz->cz_hi inclusive) are unaffected.
|
|
*
|
|
* Results:
|
|
* Always returns 0.
|
|
*
|
|
* Side effects:
|
|
* Modifies 'dm' as described in the comments for glPenDeleteNet().
|
|
*/
|
|
|
|
int
|
|
glPenDeleteFunc(cz, srcPin, dstPin, dm)
|
|
CZone *cz; /* Being passed through by srcPin..dstPin */
|
|
GCRPin *srcPin, *dstPin; /* Two pins in cz->cz_chan */
|
|
DensMap *dm; /* Remove srcPin..dstPin segment from 'dm' */
|
|
{
|
|
int n;
|
|
int lo, hi;
|
|
|
|
if (cz->cz_type == CZ_COL)
|
|
{
|
|
/* Find range of columns spanned by the net */
|
|
lo = MIN(srcPin->gcr_x, dstPin->gcr_x);
|
|
hi = MAX(srcPin->gcr_x, dstPin->gcr_x);
|
|
}
|
|
else
|
|
{
|
|
/* Find range of rows spanned by the net */
|
|
lo = MIN(srcPin->gcr_y, dstPin->gcr_y);
|
|
hi = MAX(srcPin->gcr_y, dstPin->gcr_y);
|
|
}
|
|
|
|
/* Clip so we don't modify entries of 'dm' outside of 'cz' */
|
|
lo = MAX(lo, cz->cz_lo);
|
|
lo = MIN(lo, cz->cz_hi);
|
|
hi = MIN(hi, cz->cz_hi);
|
|
hi = MAX(hi, cz->cz_lo);
|
|
|
|
/* Rip up this segment */
|
|
for (n = lo; n <= hi; n++)
|
|
dm->dm_value[n]--;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glPenCleanNet --
|
|
*
|
|
* Free the GlPoints in a net's nc_paths list.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Frees memory; resets the nc_paths list to NULL.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
glPenCleanNet(net)
|
|
NLNet *net;
|
|
{
|
|
List *list;
|
|
NetClient *nc;
|
|
|
|
nc = (NetClient *) net->nnet_cdata;
|
|
for (list = nc->nc_paths; list; list = LIST_TAIL(list))
|
|
glPathFreePerm((GlPoint *) LIST_FIRST(list));
|
|
ListDealloc(list);
|
|
nc->nc_paths = (List *) NULL;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glPenSavePath --
|
|
*
|
|
* Make a permanent copy of the GlPoint list 'path', and prepend the
|
|
* first element to the list being maintained for pNetId->netid_net's
|
|
* NetClient nc_paths field.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* See above.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
glPenSavePath(rootUse, path, pNetId)
|
|
CellUse *rootUse; /* UNUSED */
|
|
GlPoint *path; /* Path linked via gl_path pointers */
|
|
NetId *pNetId; /* Net and segment identifier */
|
|
{
|
|
GlPoint *newpath;
|
|
NetClient *nc;
|
|
|
|
nc = (NetClient *) pNetId->netid_net->nnet_cdata;
|
|
|
|
/* Keep a permanent copy of the path */
|
|
newpath = glPathCopyPerm(path);
|
|
LIST_ADD(newpath, nc->nc_paths);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glPenDensitySet --
|
|
*
|
|
* Updates the density in the gc_postDens map in each channel
|
|
* reflect all of the paths for 'net'.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* See above.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
glPenDensitySet(net)
|
|
NLNet *net;
|
|
{
|
|
NetClient *nc = (NetClient *) net->nnet_cdata;
|
|
GCRPin *srcPin, *dstPin;
|
|
GlPoint *rp;
|
|
GlPoint *path;
|
|
List *list;
|
|
NetId netid;
|
|
|
|
netid.netid_net = net;
|
|
netid.netid_seg = 0;
|
|
|
|
for (list = ((NetClient *) net->nnet_cdata)->nc_paths;
|
|
list;
|
|
list = LIST_TAIL(list))
|
|
{
|
|
path = (GlPoint *) LIST_FIRST(list);
|
|
for (rp = path; rp->gl_path; rp = rp->gl_path)
|
|
{
|
|
srcPin = rp->gl_path->gl_pin;
|
|
dstPin = rp->gl_pin;
|
|
if (dstPin->gcr_ch != srcPin->gcr_ch) dstPin = dstPin->gcr_linked;
|
|
glDensAdjust(((GlobChan *) srcPin->gcr_ch->gcr_client)->gc_postDens,
|
|
srcPin, dstPin, netid);
|
|
}
|
|
}
|
|
}
|