2017-04-25 14:41:48 +02:00
|
|
|
/* gcrRoute.c -
|
|
|
|
|
*
|
|
|
|
|
* The greedy router: Top level procedures.
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
* * 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. *
|
2017-04-25 14:41:48 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/gcr/gcrRoute.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/times.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/geometry.h"
|
|
|
|
|
#include "gcr/gcr.h"
|
|
|
|
|
#include "utils/signals.h"
|
|
|
|
|
#include "utils/malloc.h"
|
|
|
|
|
#include "utils/styles.h"
|
|
|
|
|
|
2022-10-10 11:50:15 +02:00
|
|
|
/* C99 compat */
|
|
|
|
|
#include "router/router.h"
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
int gcrRouterErrors;
|
|
|
|
|
extern int gcrStandalone;
|
|
|
|
|
|
|
|
|
|
/* Forward declarations */
|
|
|
|
|
void gcrRouteCol();
|
|
|
|
|
void gcrExtend();
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* GCRroute --
|
|
|
|
|
*
|
|
|
|
|
* Top level for the greedy channel router.
|
|
|
|
|
* Routes are already set up channel routing problem.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* The return value is the number of errors found while routing
|
|
|
|
|
* this channel.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Modifies flag bits in the channel to show the presence of routing.
|
|
|
|
|
* Calls RtrChannelError when there are errors.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
GCRroute(ch)
|
|
|
|
|
GCRChannel *ch;
|
|
|
|
|
{
|
|
|
|
|
int i, density, netId;
|
|
|
|
|
char mesg[256];
|
|
|
|
|
GCRColEl *col;
|
|
|
|
|
GCRPin *pin;
|
|
|
|
|
GCRNet *net;
|
|
|
|
|
|
|
|
|
|
/* Try river-routing across the channel if possible */
|
|
|
|
|
gcrRouterErrors = 0;
|
|
|
|
|
if (gcrRiverRoute(ch))
|
|
|
|
|
return (gcrRouterErrors);
|
|
|
|
|
|
|
|
|
|
gcrBuildNets(ch);
|
|
|
|
|
if (ch->gcr_nets == (GCRNet *) NULL)
|
|
|
|
|
return (gcrRouterErrors);
|
|
|
|
|
|
|
|
|
|
gcrSetEndDist(ch);
|
|
|
|
|
density = gcrDensity(ch);
|
2022-04-11 09:01:30 +02:00
|
|
|
/* gcrPrDensity(ch, density); */ /* Debugging */
|
2017-04-25 14:41:48 +02:00
|
|
|
if (density > ch->gcr_width)
|
|
|
|
|
{
|
|
|
|
|
(void) sprintf(mesg, "Density (%d) > channel size (%d)",
|
|
|
|
|
density, ch->gcr_width);
|
|
|
|
|
RtrChannelError(ch, ch->gcr_width, ch->gcr_length, mesg, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gcrInitCollapse(ch->gcr_width + 2);
|
|
|
|
|
gcrSetFlags(ch);
|
|
|
|
|
|
|
|
|
|
/* Process the first column */
|
|
|
|
|
gcrInitCol(ch, ch->gcr_lPins);
|
|
|
|
|
gcrExtend(ch, 0);
|
|
|
|
|
gcrPrintCol(ch, 0, GcrShowResult);
|
|
|
|
|
|
|
|
|
|
/* Process subsequent columns */
|
|
|
|
|
for (i = 1; i <= ch->gcr_length; i++)
|
|
|
|
|
{
|
|
|
|
|
if (SigInterruptPending)
|
|
|
|
|
goto bottom;
|
|
|
|
|
gcrRouteCol(ch, i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Process errors at the end */
|
|
|
|
|
col = ch->gcr_lCol;
|
|
|
|
|
pin = ch->gcr_rPins;
|
|
|
|
|
for (i = 1; i <= ch->gcr_width; i++, col++, pin++)
|
|
|
|
|
if (col->gcr_h != pin->gcr_pId)
|
|
|
|
|
{
|
|
|
|
|
netId = col->gcr_h ? col->gcr_h->gcr_Id : pin->gcr_pId->gcr_Id;
|
|
|
|
|
RtrChannelError(ch, ch->gcr_length, i,
|
|
|
|
|
"Can't make end connection", netId);
|
|
|
|
|
gcrRouterErrors++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bottom:
|
|
|
|
|
/* For debugging: print channel on screen */
|
|
|
|
|
gcrDumpResult(ch, GcrShowEnd);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We have to free up the nets here, since callers may re-arrange
|
|
|
|
|
* the channel and cause the net structure to become invalid
|
|
|
|
|
* anyway.
|
|
|
|
|
*/
|
|
|
|
|
for (net = ch->gcr_nets; net; net = net->gcr_next)
|
|
|
|
|
freeMagic((char *) net);
|
|
|
|
|
ch->gcr_nets = NULL;
|
|
|
|
|
|
|
|
|
|
return (gcrRouterErrors);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* gcrRouteCol --
|
|
|
|
|
*
|
|
|
|
|
* Route the given column in the channel.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Sets flags in the channel structure to show where routing
|
|
|
|
|
* is to be placed.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gcrRouteCol(ch, indx)
|
|
|
|
|
GCRChannel *ch;
|
|
|
|
|
int indx; /* Index of column being routed. */
|
|
|
|
|
{
|
|
|
|
|
GCRNet **gcrClassify(), **list;
|
|
|
|
|
GCRColEl *col;
|
|
|
|
|
int count;
|
|
|
|
|
|
|
|
|
|
/* Make feasible top and bottom connections */
|
|
|
|
|
gcrCheckCol(ch, indx, "Start of gcrRouteCol");
|
|
|
|
|
gcrFeasible(ch, indx);
|
|
|
|
|
gcrCheckCol(ch, indx, "After feasible connections");
|
|
|
|
|
|
|
|
|
|
/* Here I should vacate terminating tracks */
|
|
|
|
|
if (GCRNearEnd(ch, indx) &&
|
|
|
|
|
(GCREndDist < ch->gcr_length || !GCRNearEnd(ch, indx - 1)))
|
|
|
|
|
gcrMarkWanted(ch);
|
|
|
|
|
|
|
|
|
|
/* Collapse split nets in the pattern that frees the most tracks */
|
|
|
|
|
gcrCollapse(&ch->gcr_lCol, ch->gcr_width, 1, ch->gcr_width, 0);
|
|
|
|
|
gcrPickBest(ch);
|
|
|
|
|
gcrCheckCol(ch, indx, "After collapse");
|
|
|
|
|
|
|
|
|
|
col = ch->gcr_lCol;
|
|
|
|
|
|
|
|
|
|
/* Reduce the range of split nets */
|
|
|
|
|
gcrReduceRange(col, ch->gcr_width);
|
|
|
|
|
gcrCheckCol(ch, indx, "After reducing range of split nets");
|
|
|
|
|
|
|
|
|
|
/* Vacate obstructed tracks. Split to make multiple end connections */
|
|
|
|
|
gcrVacate(ch, indx);
|
|
|
|
|
|
|
|
|
|
/* Raise rising and lower falling nets */
|
|
|
|
|
list = gcrClassify(ch, &count);
|
|
|
|
|
gcrCheckCol(ch, indx, "After classifying nets");
|
|
|
|
|
gcrMakeRuns(ch, indx, list, count, TRUE);
|
|
|
|
|
gcrCheckCol(ch, indx, "After making rising/falling runs");
|
|
|
|
|
|
|
|
|
|
gcrCheckCol(ch, indx, "After vacating");
|
|
|
|
|
if (GCRNearEnd(ch, indx))
|
|
|
|
|
{
|
|
|
|
|
gcrUncollapse(ch, &ch->gcr_lCol, ch->gcr_width, 1, ch->gcr_width, 0);
|
|
|
|
|
gcrPickBest(ch);
|
|
|
|
|
}
|
|
|
|
|
gcrCheckCol(ch, indx, "After uncollapse");
|
|
|
|
|
|
|
|
|
|
/* Extend active tracks to the next column. Place contacts */
|
|
|
|
|
gcrExtend(ch, indx);
|
|
|
|
|
gcrCheckCol(ch, indx, "After widen and extend");
|
|
|
|
|
gcrPrintCol(ch, indx, GcrShowResult);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* gcrExtend --
|
|
|
|
|
*
|
|
|
|
|
* Extend dangling wires to the next column.
|
|
|
|
|
* Don't extend off the end of the channel if the wrong connection
|
|
|
|
|
* would be made.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Sets bits in the result array for the channel. Where there
|
|
|
|
|
* are blockages in the next column, adds contacts to blocked
|
|
|
|
|
* tracks for a layer switch. Clears the vertical wiring for
|
|
|
|
|
* the new column.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gcrExtend(ch, currentCol)
|
|
|
|
|
GCRChannel *ch; /* Channel being routed */
|
|
|
|
|
int currentCol; /* Column that has just been completed */
|
|
|
|
|
{
|
|
|
|
|
short *res = ch->gcr_result[currentCol];
|
|
|
|
|
GCRColEl *col = ch->gcr_lCol;
|
|
|
|
|
short *prev = (short *) NULL, *next = (short *) NULL;
|
|
|
|
|
bool hasNext, hasPrev;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
ASSERT(ch->gcr_result, "gcrExtend: ");
|
|
|
|
|
if (currentCol > 0) prev = ch->gcr_result[currentCol - 1];
|
|
|
|
|
if (currentCol <= ch->gcr_length) next = ch->gcr_result[currentCol + 1];
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Consider each track, including the pseudo-track at the
|
|
|
|
|
* bottom (0) of the channel, but not the one at the top
|
|
|
|
|
* (ch->gcr_width).
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i <= ch->gcr_width; i++)
|
|
|
|
|
{
|
|
|
|
|
if (col[1].gcr_v == col->gcr_v && col->gcr_v)
|
|
|
|
|
{
|
|
|
|
|
/* Track extends upwards */
|
|
|
|
|
res[0] |= GCRU;
|
|
|
|
|
if (i == ch->gcr_width) res[1] |= GCRU;
|
|
|
|
|
if (col->gcr_flags & GCRCC) res[0] |= GCRX;
|
|
|
|
|
if (col[1].gcr_flags & GCRCC) res[1] |= GCRX;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Don't process track if not occupied by a real net */
|
|
|
|
|
hasPrev = prev && (*prev & GCRR);
|
|
|
|
|
if (col->gcr_h == (GCRNet *) NULL)
|
|
|
|
|
{
|
|
|
|
|
if (currentCol == 0) res[0] &= ~GCRR;
|
|
|
|
|
if (hasPrev) res[0] |= GCRX;
|
|
|
|
|
col->gcr_v = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Extend net if split or another pin exists in this channel */
|
|
|
|
|
hasNext = col->gcr_hi != EMPTY
|
|
|
|
|
|| col->gcr_lo != EMPTY
|
|
|
|
|
|| GCRPin1st(col->gcr_h);
|
|
|
|
|
|
|
|
|
|
if (col->gcr_v == col->gcr_h && (hasPrev || hasNext))
|
|
|
|
|
res[0] |= GCRX;
|
|
|
|
|
|
|
|
|
|
/* Clear vertical wiring */
|
|
|
|
|
col->gcr_v = 0;
|
|
|
|
|
|
|
|
|
|
/* Terminate unsplit nets with no pins after the current column */
|
|
|
|
|
if (!hasNext) col->gcr_h = (GCRNet *) NULL;
|
|
|
|
|
else if (col->gcr_flags & GCRTE)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* If the track should be extended but can't due to a
|
|
|
|
|
* hard obstacle, then print a message and terminate it.
|
|
|
|
|
*/
|
|
|
|
|
RtrChannelError(ch, currentCol, i,
|
|
|
|
|
"Can't extend track through obstacle", col->gcr_h->gcr_Id);
|
|
|
|
|
gcrRouterErrors++;
|
|
|
|
|
col->gcr_h = (GCRNet *) NULL;
|
|
|
|
|
}
|
|
|
|
|
else if (currentCol == ch->gcr_length && i
|
|
|
|
|
&& ch->gcr_rPins[i].gcr_pId == (GCRNet *) NULL)
|
|
|
|
|
{
|
|
|
|
|
/* If track about to make a bad connection, don't extend */
|
|
|
|
|
RtrChannelError(ch, currentCol, i,
|
|
|
|
|
"Can't extend track to bad connection", col->gcr_h->gcr_Id);
|
|
|
|
|
col->gcr_h = (GCRNet *) NULL;
|
|
|
|
|
gcrRouterErrors++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Extend the net into the next column */
|
|
|
|
|
res[0] |= GCRR;
|
|
|
|
|
if (currentCol == ch->gcr_length) *next |= GCRR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Contact in next col if GCRTC */
|
|
|
|
|
if (*next & GCRTC) col->gcr_v = col->gcr_h;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (prev) prev++;
|
|
|
|
|
if (next) col->gcr_flags = *next++;
|
|
|
|
|
else col->gcr_flags= 0;
|
|
|
|
|
res++;
|
|
|
|
|
col++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
col->gcr_v = 0;
|
|
|
|
|
col->gcr_flags = 0;
|
|
|
|
|
}
|