/* check.c :
   this file belongs to the Alliance cad system sources.
   Written by Frederic Petrot. */

#ifdef pc
#undef pc
#endif
#include <stdio.h>
#include <varargs.h>
#include <limits.h>
#include MUT_H
#include MLO_H
#include MLU_H
#include MPH_H
#include MPU_H
#include SCR_H
#include "mbkgen.h"
#include "util.h"
#define ERROR 1
#define WARNING 0

/*
   Error level, Error number, arguments ... */
enum {NOPHYS, ONEPHYS, TOOPHYS, UNKNOWNLO, NOCHAN, INCONS, ROUTE, NOLAYER,
		MINWIDTH, YFAL, XBIG, XFAL, YBIG, LOPHYS, BADHSUP, BADVSUP, NOEQUIV,
		BADLAYER, BADVIA, NOTRACK, BADFACE};
static void
	error(va_alist)
va_dcl
{
va_list args;
int level, i;
FILE *f;
char *s;
static int putn;
static char *msg[] = {
	"no physical instance",
	"only one physical instance placed",
	"more than two physical instance placed",
	"unexpected logical instance '%s'",
	"the channel cannot be found from the placement",
	"instance '%s' has physical model '%s' and logical model '%s'",
	"cannot route connectors '%s' and '%s' together",
	"unable to change layer on edges of channel for connector '%s'",
	"connector '%s' changed to minimum width",
	"connector '%s' different from channel y, %d != %d, thus ignored",
	"connector '%s' is not on EAST or WEST face of the figure, thus ignored",
	"connector '%s' different from channel x, %d != %d, thus ignored",
	"connector '%s' is not on SOUTH or NORTH face of the figure, thus ignored",
	"logical external connector '%s' has a physical equivalent but is not\
	 connected into the channel",
	"horizontal channel with bad supply '%s' at (%ld, %ld)",
	"vertical channel with bad supply '%s' at (%ld, %ld)",
	"no logical external connector equivalent to phisical '%s'",
	"connector '%s' on a feed through of a different layer",
	"no via on segment end : internal failure on segment (%d, %d)-(%d, %d)",
	"not enough empty tracks for correct supplies connections",
	"bad connector face choice, %c, for the channel direction, %c"
};

	va_start(args);
	level = va_arg(args, int);
	if ((i = va_arg(args, int)) == ROUTE)
		if (level == WARNING)
			level = ERROR + 1;
	f = level == WARNING ? stdout : stderr;
	(void)fflush(stdout);
	if (!putn++)
		fputs("\n", f);
	(void)fprintf(f, "bbr %s : ", level == WARNING ? "warning" : "error");
	s = msg[i];
	(void)vfprintf(f, s, args);
	fputs("\n", f);
	va_end(args);
	if (level == ERROR)
		EXIT(1);
}

long computedensity(density, i, bound)
char *density;
long i, bound;
{
int j, k = 0;

	for (j = -9; j < 10; j++) {
		if (i + j < 0 || i + j > bound)
			continue;
/*
		if (j != 0)
			k += (int)density[i + j] / j;
		else
			k += (int)density[i + j] * 2;
*/
		k += (int)density[i + j];
	}
	return k;
}

phcon_list *
	findgoodconnector(pla, sym, pi, pf, up, down, lc, density, xcon, ycon)
phfig_list *pla, *pf;
char sym;
phins_list *pi, *up, *down;
locon_list *lc;
char *density;
long *xcon, *ycon;
{
phcon_list *pc, *foundpc = NULL;
long coordinate, rho, er, realx, realy;
long bound = sym == HOR ? (pla->XAB2 - pla->XAB1) / (SCALE_X * PITCH) :
									(pla->YAB2 - pla->YAB1) / (SCALE_X * PITCH);

#ifdef CONOP
	/* find instance connectors on the net : 
	   this is less than the best way to choose a connector, since a
	   ``global'' vision would be necessary, and it would be a little
	   to hot right now.
	   later on perhaps. */
	for (pc = pf->PHCON; pc; pc = pc->NEXT) {
		if (pc->NAME != lc->NAME || (pc->LAYER != ALU1 && pc->LAYER != ALU2))
			continue;
		xyflat(xcon, ycon, pc->XCON, pc->YCON,
					pi->XINS, pi->YINS,
					pf->XAB1, pf->YAB1, pf->XAB2, pf->YAB2,
					pi->TRANSF);
		if (!foundpc) {
			if (sym == HOR && *ycon == up->YINS) {
				foundpc = pc;
				realx = coordinate = *xcon;
				realy = *ycon;
			} else if (sym == VER && *xcon == down->XINS) {
				foundpc = pc;
				realy = coordinate = *ycon;
				realx = *xcon;
			}
		} else {
			if (sym == HOR && *ycon == up->YINS) {
				er = computedensity(density,
											(*xcon - pla->XAB1) / (SCALE_X * PITCH),
											bound);
				rho = computedensity(density,
											(coordinate - pla->XAB1) / (SCALE_X * PITCH),
											bound);
				if (er < rho || (er == rho && *xcon > coordinate)) {
					foundpc = pc;
					realx = *xcon;
					realy = *ycon;
				}
			} else  if (sym == VER && *xcon == down->XINS) {
				er = computedensity(density,
											(*ycon - pla->YAB1) / (SCALE_X * PITCH),
											bound);
				rho = computedensity(density,
											(coordinate - pla->YAB1) / (SCALE_X * PITCH),
											bound);
				if (er < rho || (er == rho && *ycon > coordinate)) {
					foundpc = pc;
					realx = *xcon;
					realy = *ycon;
				}
			}
		}
	}
	if (foundpc) {
		if (sym == HOR)
			density[(realx - pla->XAB1) / (SCALE_X * PITCH)] += (char)1;
		else
			density[(realy - pla->YAB1) / (SCALE_X * PITCH)] += (char)1;
		*xcon = realx;
		*ycon = realy;
	}
	return foundpc;
#else
	/* old manner for connector choice :
	   the first connector found in the list is the connector choosen for
	   routing.
	   this is moreless a random choice when more than a connector are
	   internally wired. */
	for (pc = pf->PHCON; pc; pc = pc->NEXT) {
		if (pc->NAME != lc->NAME || (pc->LAYER != ALU1 && pc->LAYER != ALU2))
			continue;
		xyflat(xcon, ycon, pc->XCON, pc->YCON,
					pi->XINS, pi->YINS,
					pf->XAB1, pf->YAB1, pf->XAB2, pf->YAB2,
					pi->TRANSF);
		if (sym == HOR) {
			if (*ycon == up->YINS)
				return pc;
		} else {	
			if (*xcon == down->XINS)
				return pc;
		}
	}
	return NULL;
#endif
}

/* reordonates coordinates :
   I'm retrieving the coordinates of a feed through of an instance, and
   swap these values so they are odered properly for later checks. */
static void
	ordonate(f, i, s, x1, y1, x2, y2)
phfig_list *f;
phins_list *i;
phseg_list *s;
long *x1, *y1, *x2, *y2;
{
long swap;

	xyflat(x1, y1, s->X1, s->Y1, i->XINS, i->YINS,
				f->XAB1, f->YAB1, f->XAB2, f->YAB2, i->TRANSF);
	xyflat(x2, y2, s->X2, s->Y2, i->XINS, i->YINS,
				f->XAB1, f->YAB1, f->XAB2, f->YAB2, i->TRANSF);
	if (*x1 == *x2) {
		if (*y1 > *y2) {
			swap = *y2;
			*y2 = *y1;
			*y1 = swap;
		}
	} else {
		if (*x1 > *x2) {
			swap = *x2;
			*x2 = *x1;
			*x1 = swap;
		}
	}
}

pt_list *
	findfigureconnector(pla, channel, up, down, lc, orientation)
phfig_list *pla;
channel_list *channel;
phins_list *up, *down;
locon_list *lc;
char orientation;
{
pt_list *point = NULL;
phcon_list *pc;
phfig_list *f;
phseg_list *s;
long x1, y1, x2, y2;

	for (pc = pla->PHCON; pc != NULL; pc = pc->NEXT) {
		if (pc->NAME != lc->NAME
				|| (pc->LAYER != ALU1 && pc->LAYER != ALU2))
			continue;
		if (orientation == HOR) {
			/* feed through case :
			   the connector is perhaps on an instance feed through, and should
			   therefore be routed if possible by this mean. */
			if (pc->ORIENT == NORTH) {
				f = getphfig(up->FIGNAME);
				for (s = f->PHSEG; s; s = s->NEXT) {
					/* layer check :
					   I shall have the rigth to route only on feed trough and
					   nowhere else. */
					if (s->LAYER != TALU1 && s->LAYER != TALU2)
						continue;
					/* wire length check :
					   the wire *must* cross the entire figure, so check that.
					   in fact, some feed through are to be merged before checked.
					   this should be done somewhere
					if (s->Y1 != f->YAB1 || s->Y2 != f->YAB2)
						continue; */
					ordonate(f, up, s, &x1, &y1, &x2, &y2);
					if (x1 == pc->XCON && x1 == x2 && y1 == channel->COORDINATE) {
						if (pc->LAYER != (s->LAYER == TALU1 ? ALU1 : ALU2))
							error(ERROR, BADLAYER, pc->NAME);
						addphseg(pla, s->LAYER == TALU1 ? ALU1 : ALU2, 
									s->LAYER == TALU1 ? 1 * SCALE_X : 2 * SCALE_X, 
									x1, y1, x1, pc->YCON, pc->NAME);
						break;
					}
				}
				if (s) {
					pc->USER = addptype(pc->USER, FLOPCOORD,
												(void *)getsigname(lc->SIG));
					point = addpoint(point, getsigname(lc->SIG), pc->XCON, y1,
											pc->ORIENT, pc, NULL);
					continue;
				}
			}
			if (pc->ORIENT == SOUTH) {
				f = getphfig(down->FIGNAME);
				for (s = f->PHSEG; s; s = s->NEXT) {
					if (s->LAYER != TALU1 && s->LAYER != TALU2)
						continue;
					/*
					if (s->Y1 != f->YAB1 || s->Y2 != f->YAB2)
						continue;
					*/
					ordonate(f, down, s, &x1, &y1, &x2, &y2);
					if (x1 == pc->XCON && x1 == x2 && y2 == channel->COORDINATE) {
						if (pc->LAYER != (s->LAYER == TALU1 ? ALU1 : ALU2))
							error(ERROR, BADLAYER, pc->NAME);
						addphseg(pla, s->LAYER == TALU1 ? ALU1 : ALU2, 
									s->LAYER == TALU1 ? 1 * SCALE_X : 2 * SCALE_X, 
									x1, pc->YCON, x1, y2, pc->NAME);
						break;
					}
				}
				if (s) {
					pc->USER = addptype(pc->USER, FLOPCOORD,
												(void *)getsigname(lc->SIG));
					point = addpoint(point, getsigname(lc->SIG), pc->XCON, y2,
											pc->ORIENT, pc, NULL);
					continue;
				}
			}
			/* usual case :
			   the connector should be place in the channel, on the sides of the
			   figure. */
			if (pc->YCON != channel->COORDINATE) {
				error(WARNING, YFAL, pc->NAME, pc->YCON, channel->COORDINATE);
				continue;
			}
			if (pc->ORIENT != EAST && pc->ORIENT != WEST) {
				error(WARNING, XBIG, pc->NAME);
				continue;
			}
			if (pc->LAYER != ALU2)
				error(ERROR, NOLAYER, pc->NAME);
			if (pc->WIDTH != 2 * SCALE_X) { 
				error(WARNING, MINWIDTH, pc->NAME);
				pc->WIDTH = 2 * SCALE_X; 
			}
		} else {
			/* feed through case :
			   the connector is perhaps on an instance feed through, and should
			   therefore be routed if possible by this mean. */
			if (pc->ORIENT == WEST) {
				f = getphfig(up->FIGNAME);
				for (s = f->PHSEG; s; s = s->NEXT) {
					if (s->LAYER != TALU1 && s->LAYER != TALU2)
						continue;
					/*
					if (s->X1 != f->XAB1 || s->X2 != f->XAB2)
						continue;
					*/
					ordonate(f, up, s, &x1, &y1, &x2, &y2);
					if (y1 == pc->YCON && y1 == y2 && x2 == channel->COORDINATE) {
						if (pc->LAYER != s->LAYER == TALU1 ? ALU1 : ALU2)
							error(ERROR, BADLAYER, pc->NAME);
						addphseg(pla, s->LAYER == TALU1 ? ALU1 : ALU2, 
									s->LAYER == TALU1 ? 1 * SCALE_X : 2 * SCALE_X, 
									pc->XCON, y1, x2, y1, pc->NAME);
						break;
					}
				}
				if (s) {
					pc->USER = addptype(pc->USER, FLOPCOORD,
												(void *)getsigname(lc->SIG));
					point = addpoint(point, getsigname(lc->SIG), x2, pc->YCON,
											pc->ORIENT, pc, NULL);
					continue;
				}
			}
			if (pc->ORIENT == EAST) {
				f = getphfig(down->FIGNAME);
				for (s = f->PHSEG; s; s = s->NEXT) {
					if (s->LAYER != TALU1 && s->LAYER != TALU2)
						continue;
					/*
					if (s->X1 != f->XAB1 || s->X2 != f->XAB2)
						continue;
					*/
					ordonate(f, down, s, &x1, &y1, &x2, &y2);
					if (y1 == pc->YCON && y1 == y2 && x2 == channel->COORDINATE) {
						if (pc->LAYER != s->LAYER == TALU1 ? ALU1 : ALU2)
							error(ERROR, BADLAYER, pc->NAME);
						addphseg(pla, s->LAYER == TALU1 ? ALU1 : ALU2, 
									s->LAYER == TALU1 ? 1 * SCALE_X : 2 * SCALE_X, 
									x1, y1, pc->XCON, y1, pc->NAME);
						break;
					}
				}
				if (s) {
					pc->USER = addptype(pc->USER, FLOPCOORD,
												(void *)getsigname(lc->SIG));
					point = addpoint(point, getsigname(lc->SIG), x1, pc->YCON,
											pc->ORIENT, pc, NULL);
					continue;
				}
			}
			/* usual case :
			   the connector should be place in the channel, on the sides of the
			   figure. */
			if (pc->XCON != channel->COORDINATE) {
				error(WARNING, XFAL, pc->NAME, pc->XCON, channel->COORDINATE);
				continue;
			}
			if (pc->ORIENT != SOUTH && pc->ORIENT != NORTH) {
				error(WARNING, YBIG, pc->NAME);
				continue;
			}
			if (pc->LAYER != ALU2)
				error(ERROR, NOLAYER, pc->NAME);
			if (pc->WIDTH != 2 * SCALE_X) { 
				error(WARNING, MINWIDTH, pc->NAME);
				pc->WIDTH = 2 * SCALE_X; 
			}
		}
		pc->USER = addptype(pc->USER, FLOPCOORD, (void *)getsigname(lc->SIG));
		point = addpoint(point, getsigname(lc->SIG), pc->XCON, pc->YCON,
								pc->ORIENT, pc, NULL);
	}
	return point;
}
/* checks and builds before routing :
   pla is the physical placement of *two* instances.
   net is the netlist between connectors of these two instances.
	supplies is the list of power, clock, that must be routed explictly
   without the channel router. The DATA fiels is the name of the supply,
   the TYPE is its width.
   Here I create the channel and the overall nets to be routed.
   This replaces the functions DEF_CHANNEL, NET_INSTANCE, NET_CHANNEL
   and SUPPLY, that are the netlist and placement description in custom
   approach. */
channel_list *
	checkandbuild(pla, net, supplies, userface)
phfig_list *pla;
lofig_list *net;
ptype_list *supplies;
char userface;
{
phins_list *up, *down, *pi;
phcon_list *pc;
phfig_list *pf;
long xcon, ycon, dx, x, y, xx, yy;
char sym, face;
loins_list *lup, *ldown;
locon_list *lc;
loins_list *li;
void *gp;
ptype_list *pt;
losig_list *ls;
bnet_list *supplyN = NULL, *supplyS = NULL;
channel_list *channel = NULL;
pt_list *point;
char *density; /* channel density profile in term of connector number */
ptype_list *errorlist = NULL;

	if ((up = pla->PHINS) == NULL)
		error(ERROR, NOPHYS);
	lup = getloins(net, up->INSNAME);
	sym = up->TRANSF;
	pf = getphfig(up->FIGNAME, 'P');
	if (sym == NOSYM || sym == SYM_X || sym == SYM_Y || sym == SYMXY) {
		x = up->XINS + pf->XAB2 - pf->XAB1;
		y = up->YINS + pf->YAB2 - pf->YAB1;
	}
	if (sym == ROT_P || sym == ROT_M || sym == SY_RP || sym == SY_RM) {
		x = up->XINS + pf->YAB2 - pf->YAB1;
		y = up->YINS + pf->XAB2 - pf->XAB1;
	}
	if ((down = up->NEXT) == NULL)
		error(ERROR, ONEPHYS);
	ldown = getloins(net, down->INSNAME);
	sym = down->TRANSF;
	pf = getphfig(down->FIGNAME, 'P');
	if (sym == NOSYM || sym == SYM_X || sym == SYM_Y || sym == SYMXY) {
		xx = down->XINS + pf->XAB2 - pf->XAB1;
		yy = down->YINS + pf->YAB2 - pf->YAB1;
	}
	if (sym == ROT_P || sym == ROT_M || sym == SY_RP || sym == SY_RM) {
		xx = down->XINS + pf->YAB2 - pf->YAB1;
		yy = down->YINS + pf->XAB2 - pf->XAB1;
	}
	if (down->NEXT != NULL)
		error(ERROR, TOOPHYS);
	for (li = net->LOINS; li != (loins_list *)NULL; li = li->NEXT)
		if (li != lup && li != ldown)
			error(ERROR, UNKNOWNLO, li->INSNAME);
	if (yy == up->YINS)
		sym = HOR;
	else if (y == down->YINS) {
		sym = HOR;
		gp = (void *)down;
		down = up;
		up = (phins_list *)gp;
		gp = (void *)ldown;
		ldown = lup;
		lup = (loins_list *)gp;
		dx = yy;
		yy = y;
		y = dx;
	} else if (x == down->XINS) /* left is up, right is down */
		sym = VER;
	else if (xx == up->XINS) {
		sym = VER;
		gp = (void *)down;
		down = up;
		up = (phins_list *)gp;
		gp = (void *)ldown;
		ldown = lup;
		lup = (loins_list *)gp;
		dx = xx;
		xx = x;
		x = dx;
	} else
		error(ERROR, NOCHAN);
	if (lup->FIGNAME != up->FIGNAME)
		error(ERROR, INCONS, up->INSNAME, up->FIGNAME, lup->FIGNAME);
	if (ldown->FIGNAME != down->FIGNAME)
		error(ERROR, INCONS, down->INSNAME, down->FIGNAME, ldown->FIGNAME);

	channel = addchannel(channel, "channel", NULL, NULL, sym,
								sym == HOR ? up->YINS : down->XINS);
	
	density = (char *)mbkalloc(
					(xx = ((sym == HOR ? (pla->XAB2 - pla->XAB1)
												: (pla->YAB2 - pla->YAB1))
					/ (SCALE_X * PITCH))) * sizeof(char));
	(void)memset(density, '\0', xx);
	/* skip and build :
	   the two instances are ran trough to find the physical connectors
	   corresponding to the logical ones.
		when a physical connector matches the channel routing problem, then
	   its transformed coordinates are added to the list of points to be
	   routed together, but this only if its not a declared supply.
	   the connectors to be put on perpendicular edges of the channel must
	   be placed right on the channel coordinate on the abutment box of the
	   figure. */
	for (pi = pla->PHINS; pi != (phins_list *)NULL; pi = pi->NEXT) {
		pf = getphfig(pi->FIGNAME, 'P');
		li = getloins(net, pi->INSNAME);
		for (lc = li->LOCON; lc; lc = lc->NEXT) {
			point = NULL;
			/* check for supplies :
		   	supplies are special signal that *must* not be routed by the
		   	symbolic channel router.
				they must be skept at that point. */
			gp = (void *)getsigname(lc->SIG);
			if (isvdd((char *)gp) || isvss((char *)gp))
				continue;
			for (pt = supplies; pt != NULL; pt = pt->NEXT)
				if (gp == pt->DATA) {
					gp = (void *)NULL;
					break;
				}
			/* it is a pain in c not beeing able to break or continue out of more
			   than one loop. */
			if (gp == (void *)NULL)
				continue;
			/* find instance connectors on the net */
			gp = (void *)findgoodconnector(pla, sym, pi, pf,
														up, down, lc, density, &xcon, &ycon);
			/* connector on channel :
			   the signal is routable, so let's retrieve its endpoints
			   coordinates. */
			if (gp != (void *)NULL) {
				switch (instanceface(((phcon_list *)gp)->ORIENT, pi->TRANSF)) {
					case NORTH :
						if (sym == VER)
							continue;
						face = SOUTH;
						break;
					case SOUTH :
						if (sym == VER)
							continue;
						face = NORTH;
						break;
					case EAST :
						if (sym == HOR)
							continue;
						face = WEST;
						break;
					case WEST :
						if (sym == HOR)
							continue;
						face = EAST;
						break;
				}
				point = addpoint(point, getsigname(lc->SIG),
								xcon, ycon, face, (phcon_list *)gp, NULL);
			} else {
			/* no connector on channel :
		   	this logical connector does not belong to the channel.
		   	this is either because it must not be routed, only copied up.
		   	or because it's a user mistake.
			   This case may be detected since a routed connector must be on
			   a net with another instance connector. */
				for ((loins_list *)pt = net->LOINS; (loins_list *)pt != NULL;
						(loins_list *)pt = ((loins_list *)pt)->NEXT) {
					for (gp = (void *)((loins_list *)pt)->LOCON;
							gp != (void *)NULL;
							gp = (void *)((locon_list *)gp)->NEXT) {
						if (((locon_list *)gp)->SIG == lc->SIG
								&& ((locon_list *)gp)->NAME != lc->NAME) {
							errorlist = addptype(errorlist,
															(long)((locon_list *)gp)->NAME,
															(void *)lc->NAME);
/*
							error(ERROR, ROUTE, ((locon_list *)gp)->NAME, lc->NAME);
*/
						}
					}
				}
			}
			/* add the connexion points :
			   points are put on the user field of the signals, with FLOPCOORD
			   type. */
			if (point != NULL) {
				pt = getptype(lc->SIG->USER, FLOPCOORD);
				if (pt == NULL)
					lc->SIG->USER =
							addptype(lc->SIG->USER, FLOPCOORD, (void *)point);
				else
					pt->DATA = (void *)append(pt->DATA, (chain_list *)point); 
			}
		}
	}
	mbkfree(density);
	if (errorlist)
		for (pt = errorlist; pt; pt = pt->NEXT)
			error(pt->NEXT ? WARNING : ERROR, ROUTE,
					(char *)pt->TYPE, (char *)pt->DATA);
	/* figure connectors :
	   since some connectors shall be put on channel edges, I must check
	   for there existance in the figure itself.
	   difference regarding instances : all connectors are put on the
	   list since its a user demand. */
	for (lc = net->LOCON; lc != NULL; lc = lc->NEXT) {
		/* seek for physical equivalent :
		   if a physical connector is called lc->NAME, then I have to take care
		   of it for the routing phase, but only if it is also connected with
		   instance connector inside the channel. */
		point = findfigureconnector(pla, channel, up, down, lc, sym);
		if (point != NULL) {
			pt = getptype(lc->SIG->USER, FLOPCOORD);
			if (pt == NULL)
				error(WARNING, LOPHYS, lc->NAME);
			else
				pt->DATA = (void *)append(pt->DATA, (chain_list *)point); 
		} else {
		/* adding connectors if needed :
		   since no connector is physically placed, let see if I shall not
		   add one. */
			pt = getptype(lc->SIG->USER, FLOPCOORD);
			if (pt != NULL) {
			static char randomface;
				/* random choice :
			   	since the user doesn't give any preference, I randomly choose
			   	a face for the connectors.
			   	I could also have a connector on each face, but a choice has to
			   	be done anyway. */
				switch (userface) {
					case NORTH :
						if (sym == VER)
							randomface = 0;
						else
							error(WARNING, BADFACE, userface, sym);
						break;
					case SOUTH :
						if (sym == VER)
							randomface = 1;
						else
							error(WARNING, BADFACE, userface, sym);
						break;
					case EAST :
						if (sym == HOR)
							randomface = 0;
						else
							error(WARNING, BADFACE, userface, sym);
						break;
					case WEST :
						if (sym == HOR)
							randomface = 1;
						else
							error(WARNING, BADFACE, userface, sym);
						break;
					default :
						randomface = randomface == 0 ? 1 : 0;
				}
				if (sym == HOR)
					pc = addphcon(pla,
										randomface == 0 ? EAST : WEST,
										lc->NAME,
										randomface == 0 ? pla->XAB2 : pla->XAB1,
										channel->COORDINATE, ALU2, 2 * SCALE_X);
				else
					pc = addphcon(pla,
										randomface == 0 ? NORTH : SOUTH,
										lc->NAME, channel->COORDINATE,
										randomface == 0 ? pla->YAB2 : pla->YAB1,
										ALU2, 2 * SCALE_X);

				pc->USER = addptype(pc->USER, FLOPCOORD,
											(void *)getsigname(lc->SIG));
				point = addpoint(point, getsigname(lc->SIG),
										pc->XCON, pc->YCON, pc->ORIENT, pc, NULL);
				pt->DATA = (void *)append(pt->DATA, (chain_list *)point); 
			}
		}
	}
	/* usual nets :
	   only one connector is to be routed. */
	for (ls = net->LOSIG; ls != NULL; ls = ls->NEXT) {
		/* supplies :
		   they must be skept. */
		gp = (void *)getsigname(ls);
		if (isvdd((char *)gp) || isvss((char *)gp))
			continue;
		for (pt = supplies; pt != NULL; pt = pt->NEXT)
			if (gp == pt->DATA) {
				gp = (void *)NULL;
				break;
			}
		if (gp == (void *)NULL)
			continue;
		if ((pt = getptype(ls->USER, FLOPCOORD)) != NULL)
			/* antenna ?
			   if a signal is linked to a single connector, I shall no make
			   anything on it! */
			if (((pt_list *)pt->DATA)->NEXT != NULL)
				channel->NETS = addnet(channel->NETS, getsigname(ls), pt->DATA);
			else {
				mbkfree((pt_list *)pt->DATA);
				delptype(ls->USER, FLOPCOORD);
			}
	}
	/* supplies now :
	   each and every connector of each instance is seeked for this name. */
	for (pt = supplies; pt != NULL; pt = pt->NEXT) {
		char *nameN, *nameS;
		/* supply names :
		   I choose name I'm sure no other one may collide with. */
		sprintf(buffer, "flopn%s", (char *)pt->DATA);
		nameN = (void *)namealloc(buffer);
		sprintf(buffer, "flops%s", (char *)pt->DATA);
		nameS = namealloc(buffer);
		supplyN = addnet(supplyN, nameN, NULL);
		supplyS = addnet(supplyS, nameS, NULL);
		for (li = net->LOINS; li; li = li->NEXT) {
			for (lc = li->LOCON; lc; lc = lc->NEXT) {
				if (getsigname(lc->SIG) == (char *)pt->DATA) {
					pi = getphins(pla, li->INSNAME);
					pf = getphfig(pi->FIGNAME, 'A');
					for (pc = pf->PHCON; pc; pc = pc->NEXT) {
						if (pc->NAME != lc->NAME)
							continue;
						xyflat(&x, &y, pc->XCON, pc->YCON, pi->XINS, pi->YINS,
									pf->XAB1, pf->YAB1, pf->XAB2, pf->YAB2, pi->TRANSF);
						if (channel->DIRECTION == HOR) {
							if (y == channel->COORDINATE) {
								switch (instanceface(pc->ORIENT, pi->TRANSF)) {
									case NORTH :
										supplyS->POINTS = addpoint(supplyS->POINTS,
																			nameS,
																			x, pc->WIDTH / SCALE_X,
																			SOUTH,
																			pc, pt->TYPE);
										break;
									case SOUTH :
										supplyN->POINTS = addpoint(supplyN->POINTS,
																			nameN,
																			x, pc->WIDTH / SCALE_X,
																			NORTH,
																			pc, pt->TYPE);
										break;
									default :
										continue;
								}
							}
						} else {
							if (x == channel->COORDINATE) {
								switch (instanceface(pc->ORIENT, pi->TRANSF)) {
									case WEST :
										supplyN->POINTS = addpoint(supplyN->POINTS,
																			nameN,
																			y, pc->WIDTH / SCALE_X,
																			NORTH,
																			pc, pt->TYPE);
										break;
									case EAST :
										supplyS->POINTS = addpoint(supplyS->POINTS,
																			nameS,
																			y, pc->WIDTH / SCALE_X,
																			SOUTH,
																			pc, pt->TYPE);
										break;
									default :
										continue;
								}
							}
						}
					}
				}
			}
		}
		if (supplyS->POINTS) { /* if some points exists only */
			supplyS->NEXT = channel->SUPPLIES;
			channel->SUPPLIES = supplyS;
		}
		if (supplyN->POINTS) { /* if some points exists only */
			supplyN->NEXT = channel->SUPPLIES;
			channel->SUPPLIES = supplyN;
		}
	}
	return channel;
}

/* build the block :
   copies instance connectors to abutment box, and rename them as correctly
   as possible. */
void
	makeblock(model, routed, supplies)
phfig_list *model;
channel_list *routed;
ptype_list *supplies;
{
phfig_list *pf, *channel;
phins_list *up, *down, *pi;
phcon_list *pc;
phseg_list *ps;
ptype_list *pup, *pdown, *pt;
long xcon, ycon, dx, issuply, oldXAB1, oldXAB2;
lofig_list *lf = getlofig(model->NAME, 'A');
loins_list *li;
locon_list *lcf, *lci;
char *signame;

	/* no check :
	   this fuction may be called only with 2 instance. */
	up = model->PHINS;
	down = model->PHINS->NEXT;
	/* save that stuff :
	   this is needed for good connector displacement at the end of the
	   function. */
	oldXAB1 = model->XAB1;
	oldXAB2 = model->XAB2;

	if (routed->DIRECTION == HOR) {
		if (down->YINS == routed->COORDINATE) { /* swap up and down */
			pi = down;
			down = up;
			up = pi;
		}
		channel = getphfig(routed->NAME, 'P');
		addphins(model, routed->NAME, "no5", NOSYM,
						model->XAB1, up->YINS);
		up->YINS += channel->YAB2 - channel->YAB1;
		dx = MAX(model->XAB2 - model->XAB1, channel->XAB2 - channel->XAB1);
		model->XAB2 = model->XAB1 + dx;
		model->YAB2 += channel->YAB2 - channel->YAB1;
		/* update of connectors :
		   the connectors on the surround of the abutment box of the figure are
		   copied up for later use.
		   this function strongly relie on the fact that only three instance are
		   present in the figure, and so on.
		   For extraction purposes, the internally wired physical connectors
		   must have the same name, and the only copied up connectors are the
		   one declared in the logical interface. */
		for (lcf = lf->LOCON; lcf; lcf = lcf->NEXT) {
			/* issuply :
			   now stands for supply, indicating wether a signal is a user
			   declared supply or *VDD* or *VSS*. */
			signame = getsigname(lcf->SIG);
			issuply = 0;
			for (pt = supplies; pt; pt = pt->NEXT)
				if ((char *)(pt->DATA) == signame) {
					issuply++;
					break;
				}
			if (isvdd(signame) || isvss(signame))
				issuply++;
			for (li = lf->LOINS; li; li = li->NEXT) {
				if (issuply) {
					/* only two instances :
					   here I choose to use the name of the logical connector
					   of the cell, since its what the user demands, but
					   the extractor will cry the hell out of me. */
					if (li->FIGNAME == up->FIGNAME)
						(void)strcat(strcpy(buffer, lcf->NAME), ""); /* "up" */
					else
						(void)strcat(strcpy(buffer, lcf->NAME), ""); /* "down" */
				} else
					(void)strcpy(buffer, lcf->NAME);
				for (lci = li->LOCON; lci; lci = lci->NEXT) {
					if (lcf->SIG == lci->SIG) {
						pf = getphfig(li->FIGNAME, 'P');
						pi = getphins(model, li->INSNAME);
						for (pc = pf->PHCON; pc; pc = pc->NEXT) {
							/* name matching rules :
							   I define some rules that say, if this logical connector
							   has name x, then its physical equivalent is y. */
							if (pc->NAME != lci->NAME)
								continue;
							/*
							if (issuply == 0 && pc->NAME != lci->NAME)
								continue;
							if (issuply == 1 && !((isvdd(lci->NAME) && isvdd(pc->NAME))
									|| (isvss(lci->NAME) && isvss(pc->NAME))))
								continue;
							*/
							xyflat(&xcon, &ycon, pc->XCON, pc->YCON,
										pi->XINS, pi->YINS,
										pf->XAB1, pf->YAB1, pf->XAB2, pf->YAB2,
										pi->TRANSF);
							switch (instanceface(pc->ORIENT, pi->TRANSF)) {
								case WEST :
									addphcon(model, WEST, buffer, model->XAB1, ycon,
												pc->LAYER, pc->WIDTH);
									if (xcon > model->XAB1)
										addphseg(model, pc->LAYER, pc->WIDTH,
													model->XAB1, ycon, xcon, ycon,
													(char *)NULL);
									continue;
								case EAST :
									addphcon(model, EAST, buffer, model->XAB2, ycon,
												pc->LAYER, pc->WIDTH);
									if (xcon < model->XAB2)
										addphseg(model, pc->LAYER, pc->WIDTH, xcon, ycon,
													model->XAB2, ycon, (char *)NULL);
									continue;
								case SOUTH :
									if (pi == up || pi->FIGNAME == channel->NAME)
										continue;
									addphcon(model, SOUTH, buffer, xcon, model->YAB1,
												pc->LAYER, pc->WIDTH);
									if (ycon > model->YAB1)
										addphseg(model, pc->LAYER, pc->WIDTH, xcon,
													model->YAB1, xcon, ycon, (char *)NULL);
									continue;
								case NORTH :
									if (pi == down || pi->FIGNAME == channel->NAME)
										continue;
									addphcon(model, NORTH, buffer, xcon, model->YAB2,
												pc->LAYER, pc->WIDTH);
									if (ycon < model->YAB2)
										addphseg(model, pc->LAYER, pc->WIDTH, xcon, ycon,
													xcon, model->YAB2, (char *)NULL);
									continue;
							}
						}
					}
				}
			}
		}
	} else { /* vertical channel */
		if (up->XINS == routed->COORDINATE) { /* swap left and right */
			/* left is up, right is down */
			pi = down;
			down = up;
			up = pi;
		}
		channel = getphfig(routed->NAME, 'P');
		addphins(model, routed->NAME, "no5", SY_RP,
					down->XINS, model->YAB1);
		down->XINS += channel->YAB2 - channel->YAB1;
		model->XAB2 += channel->YAB2 - channel->YAB1;
		dx = MAX(model->YAB2 - model->YAB1,
						channel->XAB2 - channel->XAB1); 
		model->YAB2 = model->YAB1 + dx;
		/* update of connectors :
		   the connectors on the surround of the abutment box of the figure are
		   copied up for later use.
		   this function strongly relie on the fact that only three instance are
		   present in the figure, and so on. */
		for (lcf = lf->LOCON; lcf; lcf = lcf->NEXT) {
			/* issuply :
			   now stands for supply, indicating wether a signal is a user
			   declared supply or *VDD* or *VSS*. */
			signame = getsigname(lcf->SIG);
			issuply = 0;
			for (pt = supplies; pt; pt = pt->NEXT)
				if ((char *)(pt->DATA) == signame) {
					issuply++;
					break;
				}
			if (isvdd(signame) || isvss(signame))
				issuply++;
			for (li = lf->LOINS; li; li = li->NEXT) {
#if 0
				if (issuply) {
					/* only two instances */
					if (li->FIGNAME == up->FIGNAME)
						(void)strcat(strcpy(buffer, lcf->NAME), "left");
					else
						(void)strcat(strcpy(buffer, lcf->NAME), "right");
				} else
#endif			
					(void)strcpy(buffer, lcf->NAME);
				for (lci = li->LOCON; lci; lci = lci->NEXT) {
					if (lcf->SIG == lci->SIG) {
						pf = getphfig(li->FIGNAME, 'P');
						pi = getphins(model, li->INSNAME);
						for (pc = pf->PHCON; pc; pc = pc->NEXT) {
							if (pc->NAME != lci->NAME)
								continue;
							xyflat(&xcon, &ycon, pc->XCON, pc->YCON,
										pi->XINS, pi->YINS,
										pf->XAB1, pf->YAB1, pf->XAB2, pf->YAB2,
										pi->TRANSF);
							switch (instanceface(pc->ORIENT, pi->TRANSF)) {
								case WEST :
									if (pi == down || pi->FIGNAME == channel->NAME)
										continue;
									addphcon(model, WEST, buffer, model->XAB1, ycon,
												pc->LAYER, pc->WIDTH);
									if (xcon > model->XAB1)
										addphseg(model, pc->LAYER, pc->WIDTH,
													model->XAB1, ycon, xcon, ycon,
													(char *)NULL);
									continue;
								case EAST :
									if (pi == up || pi->FIGNAME == channel->NAME)
										continue;
									addphcon(model, EAST, buffer, model->XAB2, ycon,
												pc->LAYER, pc->WIDTH);
									if (xcon < model->XAB2)
										addphseg(model, pc->LAYER, pc->WIDTH, xcon, ycon,
													model->XAB2, ycon, (char *)NULL);
									continue;
								case SOUTH :
									addphcon(model, SOUTH, buffer, xcon, model->YAB1,
												pc->LAYER, pc->WIDTH);
									if (ycon > model->YAB1)
										addphseg(model, pc->LAYER, pc->WIDTH, xcon,
													model->YAB1, xcon, ycon, (char *)NULL);
									continue;
								case NORTH :
									addphcon(model, NORTH, buffer, xcon, model->YAB2,
												pc->LAYER, pc->WIDTH);
									if (ycon < model->YAB2)
										addphseg(model, pc->LAYER, pc->WIDTH, xcon, ycon,
													xcon, model->YAB2, (char *)NULL);
									continue;
							}
						}
					}
				}
			}
		}
	}
	/* supplies :
	   as usual, they are to be treated a little strangely.
	   The added connectors on the physical instance are given the name
	   of the signal they are connected on.
	   So I look for the logical figure connector that has this name for
	   signal, and I copy the channel physical connector in the block with
	   this name. */
	pi = getphins(model, "no5");
	for (lcf = lf->LOCON; lcf; lcf = lcf->NEXT) {
		signame = getsigname(lcf->SIG);
		for (pc = channel->PHCON; pc; pc = pc->NEXT) {
			if (pc->NAME == signame)
				strcpy(buffer, lcf->NAME);
			else if (strlen(pc->NAME) > 4 &&
					!strncmp(pc->NAME, "flop", 4) &&
					!strcmp(&(pc->NAME)[5], signame)) {
				if (pc->NAME[4] == 'n')
					strcat(strcpy(buffer, &(pc->NAME)[5]), 
								routed->DIRECTION == HOR ? "up" : "left");
				else if (pc->NAME[4] == 's')
					strcat(strcpy(buffer, &(pc->NAME)[5]),
								routed->DIRECTION == HOR ? "down" : "right");
			} else
				continue;
			if (routed->DIRECTION == HOR) {
				xyflat(&xcon, &ycon, pc->XCON, pc->YCON, pi->XINS, pi->YINS,
							channel->XAB1, channel->YAB1,
							channel->XAB2, channel->YAB2, pi->TRANSF);
				switch (instanceface(pc->ORIENT, pi->TRANSF)) {
					case WEST :
						addphcon(model, WEST, buffer, model->XAB1, ycon,
									pc->LAYER, pc->WIDTH);
						if (xcon > model->XAB1)
							addphseg(model, pc->LAYER, pc->WIDTH, model->XAB1, ycon,
										xcon, ycon, (char *)NULL);
						continue;
					case EAST :
						addphcon(model, EAST, buffer, model->XAB2, ycon,
									pc->LAYER, pc->WIDTH);
						if (xcon < model->XAB2)
							addphseg(model, pc->LAYER, pc->WIDTH, xcon, ycon,
										model->XAB2, ycon, (char *)NULL);
						continue;
				}
			} else {
				xyflat(&xcon, &ycon, pc->XCON, pc->YCON, pi->XINS, pi->YINS,
							channel->XAB1, channel->YAB1,
							channel->XAB2, channel->YAB2, pi->TRANSF);
				switch (instanceface(pc->ORIENT, pi->TRANSF)) {
					case SOUTH :
						addphcon(model, SOUTH, buffer, xcon, model->YAB1,
									pc->LAYER, pc->WIDTH);
						if (ycon > model->YAB1)
							addphseg(model, pc->LAYER, pc->WIDTH, xcon,
										model->YAB1, xcon, ycon, (char *)NULL);
						continue;
					case NORTH :
						addphcon(model, NORTH, buffer, xcon, model->YAB2,
									pc->LAYER, pc->WIDTH);
						if (ycon < model->YAB2)
							addphseg(model, pc->LAYER, pc->WIDTH, xcon, ycon,
										xcon, model->YAB2, (char *)NULL);
						continue;
				}
			}
		}
	}
#ifdef COMPACT
	savephfig(channel);
#endif
	flattenphfig(model, "no5", NO);
	/* end of it :
	   I must now move figure connectors at the point where its routed segment
	   crosses the abutment box.
	   This implies one more constraint : the name of the signal, yes signal,
	   that is on its logical equivalent, must be the in the USER field of the
		connector. */
	for (pc = model->PHCON; pc; pc = pc->NEXT) {
		if ((pt = getptype(pc->USER, FLOPCOORD)) == NULL)
			continue;
		for (ps = model->PHSEG; ps; ps = ps->NEXT) {
			if (ps->NAME != (char *)pt->DATA)
				continue;
			if (ps->TYPE == LEFT || ps->TYPE == RIGHT) {
				if (ps->X1 == model->XAB1) {
					pc->YCON = ps->Y1;
					pc->XCON = model->XAB1;
				} else if (ps->X2 == model->XAB2) {
					pc->YCON = ps->Y1;
					pc->XCON = model->XAB2;
				}
			} else {
				if (ps->Y1 == model->YAB1) {
					pc->XCON = ps->X1;
					pc->YCON = model->YAB1;
				} else if (ps->Y2 == model->YAB2) {
					pc->XCON = ps->X1;
					pc->YCON = model->YAB2;
				}
			}
		}
		delptype(pc->USER, FLOPCOORD);
	}
}

void
	routechannel(model, channel)
phfig_list *model;
channel_list *channel;
{
bnet_list *net;
pt_list *point;
ptype_list *ptheadG = NULL;
ptype_list *ptheadN = NULL;
ptype_list *ptheadW = NULL;
ptype_list *ptheadS = NULL;
ptype_list *ptheadE = NULL;
ptype_list *headG = NULL;
ptype_list *headN = NULL;
ptype_list *headW = NULL;
ptype_list *headS = NULL;
ptype_list *headE = NULL;
ptype_list *ptype, *p;
ConnectorList *addSCR(), *scrret;
ConnectorList *scrheadS = NULL;
ConnectorList *scrheadN = NULL;
ConnectorList *scrheadW = NULL;
ConnectorList *scrheadE = NULL;
long x, y, xG;
long coordN, coordS, coordW, coordE ;
long index;
char face;
long cw, ch;
SegmentList *sh, *sv;
ViasList *vias;
int flagN = 0, flagS = 0;
long shiftN, shiftS;
int xaux;

	for (net = channel->NETS; net; net = net->NEXT) {
		for (point = net->POINTS; point; point = point->NEXT) {
			if (channel->DIRECTION == HOR) {
				switch (point->FACE) {
					case SOUTH :
						ptheadG = addptype(ptheadG, point->X, (void *)point);
						ptheadS = addptype(ptheadS, point->X, (void *)point);
						break;
					case NORTH :
						ptheadG = addptype(ptheadG, point->X, (void *)point);
						ptheadN = addptype(ptheadN, point->X, (void *)point);
						break;
					case WEST :
						ptheadW = addptype(ptheadW, point->Y, (void *)point);
						break;
					case EAST :
						ptheadE = addptype(ptheadE, point->Y, (void *)point);
						break;
				}
			} else {
				/* In fact, only the X coordinate is of uility, so rotate them */
				x = point->X;
				point->X = point->Y;
				point->Y = x;
				switch (point->FACE) {
					case WEST :
						ptheadG = addptype(ptheadG, point->X, (void *)point);
						ptheadS = addptype(ptheadS, point->X, (void *)point);
						break;
					case EAST :
						ptheadG = addptype(ptheadG, point->X, (void *)point);
						ptheadN = addptype(ptheadN, point->X, (void *)point);
						break;
					case SOUTH :
						ptheadW = addptype(ptheadW, point->Y, (void *)point);
						break;
					case NORTH :
						ptheadE = addptype(ptheadE, point->Y, (void *)point);
						break;
				}
			}
		}
	}

	ptheadS = sort_ptype(ptheadS);
	ptheadN = sort_ptype(ptheadN);
	ptheadE = sort_ptype(ptheadE);
	ptheadW = sort_ptype(ptheadW);
	ptheadG = sort_ptype(ptheadG);

	/* routing grid definition :
	   If the space between the 'current' point and the next connector is greater
	   than twice the pitch, then insert a grid step, else add a grid step at the
	   connector coordinates.
	   Both North and South connector lists are used here, in order, I hope, to
	   minimize the number of elbows later on. */
	cw = 1;
	xaux = model->XAB1 / SCALE_X;
	for (ptype = ptheadG; ptype; ptype = ptype->NEXT) {
		x = ((pt_list *)ptype->DATA)->X ;
		while (x - xaux >= 2 * PITCH * SCALE_X) {
			headG = addptype(headG, cw++, (void *)addpoint(NULL, NULL,
										xaux + PITCH * SCALE_X, 0, GRID, NULL, NULL));
			xaux += PITCH * SCALE_X;
		}
		if (x - xaux < PITCH * SCALE_X) { /* if two connectors are too close */
			if (ptype->NEXT == NULL) { /* need one more routing grid! */
				headG = addptype(headG, cw++, (void *)addpoint(NULL, NULL,
										xaux + PITCH * SCALE_X, 0, GRID, NULL, NULL));
				headG = addptype(headG, cw++, (void *)addpoint(NULL, NULL,
										xaux + 2 * PITCH * SCALE_X, 0, GRID, NULL, NULL));
				break;
			}
			continue;
		}
		headG = addptype(headG, cw++, (void *)ptype->DATA);
		xaux = ((pt_list *)ptype->DATA)->X;
	}
	freeptype(ptheadG);
	/* connector adjustment on grid :
	   Each connectors of each list is affected to a routing grid, using the
	   next free rightmost grid.
	   By construction,it is garanteed that all connectors have a rightmost
	   grid step. */
	p = headG = (ptype_list *)reverse((chain_list *)headG);
	index = p->TYPE;
	xG = ((pt_list *)p->DATA)->X;
	/* by construction, two connectors can't go on the same grid step */
	for (ptype = ptheadN; ptype != NULL; ptype = ptype->NEXT) {
		xaux = ((pt_list *)ptype->DATA)->X;
		while (xaux > xG) {
			p = p->NEXT;
			if (p == NULL) {
				fprintf(stderr, "Correct construction failed, check grid!\n");
				exit(12);
			}
			index = p->TYPE;
			xG = ((pt_list *)p->DATA)->X;
		}
		if (headN && headN->TYPE == index) {
			if (p && index == p->TYPE)
				p = p->NEXT;
			if (p != NULL) {
				index = p->TYPE;
				xG = ((pt_list *)p->DATA)->X;
			} else {
				index++;
				xG += PITCH * SCALE_X;
			}
		}
		/* are off grid adjustment needed */
		if (xaux < xG)
			flagN = 1;
		headN = addptype(headN, index, (void *)ptype->DATA);
		scrheadN = addSCR(scrheadN, 0, index, &scrret);
		((pt_list *)ptype->DATA)->SCR = scrret;
	}
	freeptype(ptheadN);

	p = headG;
	xG = ((pt_list *)p->DATA)->X;
	index = p->TYPE;
	for (ptype = ptheadS; ptype != NULL; ptype = ptype->NEXT) {
		xaux = ((pt_list *)ptype->DATA)->X ;
		while (xaux > xG) {
			p = p->NEXT;
			if (p == NULL) {
				fprintf(stderr, "Correct construction failed, check grid!\n");
				exit(12);
			}
			index = p->TYPE;
			xG = ((pt_list *)p->DATA)->X;
		}
		if (headS && headS->TYPE == index) {
			if (p && index == p->TYPE)
				p = p->NEXT;
			if (p != NULL) {
				index = p->TYPE;
				xG = ((pt_list *)p->DATA)->X;
			} else {
				index++;
				xG += PITCH * SCALE_X;
			}
		}
		/* are off grid adjustment needed */
		if (xaux < xG)
			flagS = 1;

		headS = addptype(headS, index, (void *)ptype->DATA);
		scrheadS = addSCR(scrheadS, 0, index, &scrret);
		((pt_list *)ptype->DATA)->SCR = scrret;
	}
	freeptype(ptheadS);

	cw = cw > index ? cw : index;
	for (index = 1, ptype = ptheadE; ptype; ptype = ptype->NEXT) {
		scrheadE = addSCR(scrheadE, 0, index++, &scrret);
		((pt_list *)ptype->DATA)->SCR = scrret;
	}
	freeptype(ptheadE);

	for (index = 1, ptype = ptheadW; ptype; ptype = ptype->NEXT) {
		scrheadW = addSCR(scrheadW, 0, index++, &scrret);
		((pt_list *)ptype->DATA)->SCR = scrret;
	}
	freeptype(ptheadW);

	for (index = 1, net = channel->NETS; net; net = net ->NEXT) {
		for (point = net ->POINTS; point; point = point ->NEXT)
			point->SCR->ConName = index;
		index++;
	}

	ch = 0;
	sh = sv = NULL;
	vias = NULL;
#ifdef SCRDEBUG
	if (headN == NULL || headS == NULL) {
		fprintf(stderr, "Only the %s side of the channel has connectors\n",
					headN == NULL ? "SOUTH" : "NORTH");
	}
#endif
	/* to debug scr when it fails! */
#ifdef SCRDEBUG
	puts("North");
	viewscr(scrheadN);
	puts("South");
	viewscr(scrheadS);
	puts("East");
	viewscr(scrheadE);
	puts("West");
	viewscr(scrheadW);
#endif
	SymbolicChannelRouter(&scrheadN, &scrheadS, &scrheadW, &scrheadE,
									&cw, &ch, &sh, &sv, &vias);
#ifdef SCRDEBUG
	scrtopitched(channel, sh, sv, vias, cw, ch);
	shiftN = shiftS = 0;
#endif
#ifndef RANDOM
	bboxshift(model, &shiftN, &shiftS);
#endif
	scrtombk(model, channel, sh, sv, vias, cw, ch,
					headG, headN, headS, flagN, flagS, shiftN, shiftS);
	freeptype(headG);
	freeptype(headN);
	freeptype(headS);
}

/* merge :
   merges colinear symbolic segments since the pitchless part of the router
   is quite generous with segments. */
int
	vercmp(s1, s2)
phseg_list **s1, **s2;
{
	/* X1 equals X2, since it's a vertical segment */
	return (*s1)->X1 - (*s2)->X1 ? (*s1)->X1 - (*s2)->X1 : (*s1)->Y1 - (*s2)->Y1;
}

#define TOBEDELETED 1

/* vertical unification :
   I only create vertical splitted segments with the algorithm, so I
   shall only work on vertical segments! */
void
	verticalmerge(fig)
phfig_list *fig;
{
phseg_list *seg;
long vs = 0;
phseg_list **vertab;
int i, j;

	for (seg = fig->PHSEG; seg; seg = seg->NEXT) {
		seg->USER = NULL;
		if ((seg->TYPE == UP || seg->TYPE == DOWN)
			 && seg->LAYER == ALU1 && seg->WIDTH == 1 * SCALE_X)
			vs++;
	}

	vertab = (phseg_list **)mbkalloc(vs * sizeof(phseg_list *));
	
	vs = 0;
	for (seg = fig->PHSEG; seg; seg = seg->NEXT)
		if ((seg->TYPE == UP || seg->TYPE == DOWN)
			 && seg->LAYER == ALU1 && seg->WIDTH == 1 * SCALE_X)
			vertab[vs++] = seg;
	/* Be careful :
	   the USER field is now corrupted to know if a segment is to be deleted or
	   not.
	   A NULL means keep it, a non NULL means destroy it. */
	qsort((char *)vertab, vs, sizeof(phseg_list *), vercmp);

	for (i = 0; i < vs; i = j) {
		for (j = i + 1; j < vs; j++) {
			if (vertab[i]->X1 != vertab[j]->X1)
				break;
			if (vertab[i]->Y2 == vertab[j]->Y1) {
				vertab[i]->Y2 = vertab[j]->Y2;
				vertab[j]->USER = (ptype_list *)TOBEDELETED;
			} else
				i = j;
		}
	}
	destroysegments(fig, tobedeleted);
	mbkfree((void *)vertab);
}

int
	tobedeleted(seg)
phseg_list *seg;
{
	return (int)seg->USER;
}

int
	null(seg)
phseg_list *seg;
{
	return seg->X1 == seg->X2 && seg->Y1 == seg->Y2;
}

void
	destroysegments(fig, testfunc)
phfig_list *fig;
int (*testfunc)();
{
phseg_list **ppseg;
phseg_list *next;

	for (ppseg = &fig->PHSEG; *ppseg != NULL;) {
		if (testfunc(*ppseg)) {
			next = (*ppseg)->NEXT;
			mbkfree(*ppseg);
			*ppseg = next;
		} else
			ppseg = &(*ppseg)->NEXT;
	}
}

void
	statistics(f, i, j, k)
phfig_list *f;
int *i, *j, *k;
{
phseg_list *s;
phvia_list *v;

	for (*i = *j = 0, s = f->PHSEG; s; s = s->NEXT)
		if (s->LAYER == ALU2)
			(*i) += (s->TYPE == LEFT || s->TYPE == RIGHT) ? s->X2 - s->X1 : s->Y2 - s->Y1;
		else if (s->LAYER == ALU1)
			(*j) += (s->TYPE == LEFT || s->TYPE == RIGHT) ? s->X2 - s->X1 : s->Y2 - s->Y1;

	for (*k = 0, v = f->PHVIA; v; v = v->NEXT)
		if (v->TYPE == CONT_VIA)
			(*k)++;

	(*i) /= SCALE_X;
	(*j) /= SCALE_X;
}

/* eliminates vias :
   this brute force algo destroyes really unacceptable layer changes.
   it is not at all a nice via eraser. */

int
	tobedeletedv(via)
phvia_list *via;
{
	return (int)via->USER;
}

void
	destroyvias(fig, testfunc)
phfig_list *fig;
int (*testfunc)();
{
phvia_list **ppvia;
phvia_list *next;

	for (ppvia = &fig->PHVIA; *ppvia != NULL;) {
		if (testfunc(*ppvia)) {
			next = (*ppvia)->NEXT;
			mbkfree(*ppvia);
			*ppvia = next;
		} else
			ppvia = &(*ppvia)->NEXT;
	}
}

int
	xscmp(s1, s2)
phseg_list **s1, **s2;
{
	return (*s1)->X1 - (*s2)->X1;
}

/* be careful :
   this functions can be used only at the very end of processing.
   otherwise some strange short cuts can be taken! */
void
	changelayer(fig)
phfig_list *fig;
{
phseg_list *seg;
phvia_list *via;
long s = 0;
phseg_list **stab;
int i, j, flag;

	for (seg = fig->PHSEG; seg; seg = seg->NEXT)
		s++;
	stab = (phseg_list **)mbkalloc(s * sizeof(phseg_list *));
	s = 0;
	for (seg = fig->PHSEG; seg; seg = seg->NEXT)
		stab[s++] = seg;
	qsort((char *)stab, s, sizeof(phseg_list *), xscmp);

	for (i = 0; i < s; i++) {
		/* conditions :
		   Edge wire should not be touched, neither alu1 because of the channel
		   direction. */
		if (stab[i]->TYPE == UP || stab[i]->TYPE == DOWN
				|| stab[i]->LAYER == ALU1
				|| stab[i]->WIDTH != 1 * SCALE_X
				|| stab[i]->X1 == fig->XAB1 || stab[i]->X2 == fig->XAB2)
			continue;
		flag = 0;
		for (j = i + 1; j < s; j++) {
			if (stab[j]->X1 >= stab[i]->X2)
				break;
			if (stab[j]->TYPE == LEFT || stab[j]->TYPE == RIGHT)
				continue;
			if (stab[j]->X1 > stab[i]->X1 && stab[j]->X2 < stab[i]->X2
					&& stab[j]->Y1 < stab[i]->Y1 && stab[j]->Y2 > stab[i]->Y1) {
				flag = 1;
				break;
			}
		}
		if (!flag) {
			stab[i]->LAYER = ALU1;
			stab[i]->WIDTH = 1 * SCALE_X;
			/* mark via :
			   the via to be eliminated are first marked, then deleted.
				since the number of vias to be erase is ridiculously small,
			   there is no need for fancy qsort and bsearch here. */
			for (via = fig->PHVIA; via; via = via->NEXT) {
				if (via->XVIA == stab[i]->X1 && via->YVIA == stab[i]->Y1) {
					via->USER = (ptype_list *)TOBEDELETED;
					if (!flag)
						flag++;
					else {
						flag++;
						break;
					}
				}
				if (via->XVIA == stab[i]->X2 && via->YVIA == stab[i]->Y2) {
					via->USER = (ptype_list *)TOBEDELETED;
					if (!flag)
						flag++;
					else {
						flag++;
						break;
					}
				}
			}
			if (flag != 2)
				error(ERROR, BADVIA, stab[i]->X1, stab[i]->Y1,
											stab[i]->X2, stab[i]->Y2);
		}
	}
	destroyvias(fig, tobedeletedv);
	mbkfree((void *)stab);
}

/* some new routines :
   these routines are needed in order to try to connect together the two
   wires of a supply, to avoid extractor complaints. */
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
static char *
	findfreetracks(ch)
phfig_list *ch;
{
long ymin = ch->YAB2, ymax = ch->YAB1;
char *profil = (char *)mbkalloc((ch->XAB2 - ch->XAB1 + 1) / SCALE_X * sizeof(char));
phcon_list *con;
phseg_list *seg;
phvia_list *via;
int i, j, k; /* index to traverse the channel profile */

	(void)memset(profil, '\0', (ch->XAB2 - ch->XAB1) / SCALE_X);
	/* boundaries :
	   find the boundaries of the relevant part of the ch to be checked
	   for free tracks.
	   this is given by the closest supplies from the abutment box.
	   since there is much less connectors than segments in the figure
	   and since the relevant information is also there, I use connectors
	   in finding this boundaries. By the way, the connectors are always
	   on the east or west side of the channel. */
	for (con = ch->PHCON; con; con = con->NEXT)
		if (!strncmp(con->NAME, "flop", 4))
			if ((con->NAME)[4] == 's')
				ymin = min(ymin, con->YCON - con->WIDTH / 2 + con->WIDTH % 2 + 1);
			else if ((con->NAME)[4] == 'n')
				ymax = max(ymax, con->YCON + con->WIDTH / 2 - con->WIDTH % 2 - 1);

	for (seg = ch->PHSEG; seg; seg = seg->NEXT)
		if (seg->LAYER == ALU1 && !(seg->Y1 > ymax && seg->Y2 < ymin)) {
			if (seg->TYPE == VER)
				for (i = seg->X1 - seg->WIDTH / 2 - seg->WIDTH % 2;
						i <= seg->X1 + seg->WIDTH / 2 + seg->WIDTH % 2; i += SCALE_X)
					profil[(i - ch->XAB1) / SCALE_X] = '\1';
			else
				for (i = seg->X1 - 1 * SCALE_X;
						i <= seg->X2 + 1 * SCALE_X; i += SCALE_X)
					profil[(i - ch->XAB1) / SCALE_X] = '\1';
		}
	for (via = ch->PHVIA; via; via = via->NEXT)
		if (!(via->YVIA > ymax && via->YVIA < ymin)) {
			profil[(via->XVIA - ch->XAB1) / SCALE_X] = '\1';
			if (via->XVIA < ch->XAB2)
				profil[(via->XVIA - ch->XAB1) / SCALE_X - 1] = '\1';
			if (via->XVIA > ch->XAB1)
				profil[(via->XVIA - ch->XAB1) / SCALE_X + 1] = '\1';
		}
	/* mark tracks :
	   until now, all has been done on a lambda basis, now, add AL_AL space on
	   edges, so some wire can be drawn. */
	for (i = 0; i <= (ch->XAB2 - ch->XAB1) / SCALE_X; i++) {
		if (!profil[i])
			continue;
		/* tough job :
		   Since I must ensure proper drc rules on both side, two
		   indexes are necesarry : k to go downward, without any side effects,
		   since it may not alter a not yet done job, and : j, much harder,
		   that will have to skip down to zero if the current track is already
		   used, for good propagation. */
		for (k = j = 1; j < AL_AL; j++, k++) {
			if (i - k >= 0)
				profil[i - k] = '\1';
			if (i + j <= (ch->XAB2 - ch->XAB1) / SCALE_X) {
				if (profil[i + j]) {
					i += j;
					j = 0;
				} else
					profil[i + j] = '\1';
			}
		}
		i += j;
	}
#ifdef SCRDEBUG
	/* debug :
	   poly wires are drawn where I guess I've the right to go. */
	for (i = 0; i <= (ch->XAB2 - ch->XAB1) / SCALE_X; i++) {
		if (profil[i])
			continue;
		addphseg(ch, NDIF, 1 * SCALE_X,
					ch->XAB1 + (i * SCALE_X), ymin,
					ch->XAB1 + (i * SCALE_X), ymax, "trou_sans_fin");
	}
	savephfig(ch);
#endif
	return profil;
}

/* list of supplies :
   build a list of supplies to route together, and route them.
   supplies on a single edge of the channel are renamed with the user
   given name, supplies on both sides are tied, and given the user name. */
static ptype_list *
	adddown(link, seg)
ptype_list *link;
phseg_list *seg;
{
ptype_list *pt;

	for (pt = link; pt; pt = pt->NEXT)
		if (pt->DATA == (void *)NULL)
			continue;
		else if (!strcmp(&(seg->NAME)[5], &(((phseg_list *)pt->DATA)->NAME)[5]))
			break;

	if (!pt)
		return addptype(link, (long)seg, (void *)NULL);

	pt->TYPE = (long)seg;
	return link;
}

static ptype_list *
	addup(link, seg)
ptype_list *link;
phseg_list *seg;
{
ptype_list *pt;

	for (pt = link; pt; pt = pt->NEXT)
		if (pt->TYPE == 0L)
			continue;
		else if (!strcmp(&(seg->NAME)[5], &(((phseg_list *)pt->TYPE)->NAME)[5]))
			break;

	if (!pt)
		return addptype(link, 0L, (void *)seg);

	pt->DATA = (void *)seg;
	return link;
}

void
	connectsupplies(ch)
phfig_list *ch;
{
ptype_list *link = NULL; /* TYPE field is up, DATA field is down */
ptype_list *pt;
phseg_list *seg, *tab;
phcon_list *con;
char *freetracks;
int i, j, k, track, n = 0, width;

	/* double powers :
	   build a structure with informations on supplies segments. */
	for (seg = ch->PHSEG; seg; seg = seg->NEXT)
		if (seg->NAME && !strncmp(seg->NAME, "flop", 4))
			if ((seg->NAME)[4] == 's')
				link = adddown(link, seg);
			else if ((seg->NAME)[4] == 'n')
				link = addup(link, seg);

	/* :
	   get topology of the channel from an empty track point of view. */
	freetracks = findfreetracks(ch);
	/* name and all :
	   supplies are treated like ordinary wires, and there name changed
	   to the initial one, erasing the flop[n/s] that marked them as supplies.a*/
	for (con = ch->PHCON; con; con = con->NEXT)
		if (con->NAME && !strncmp(con->NAME, "flop", 4))
			if ((con->NAME)[4] == 's' || (con->NAME)[4] == 'n')
				con->NAME = namealloc(&(con->NAME)[5]);
	for (seg = ch->PHSEG; seg; seg = seg->NEXT)
		if (seg->NAME && !strncmp(seg->NAME, "flop", 4))
			if ((seg->NAME)[4] == 's' || (seg->NAME)[4] == 'n')
				seg->NAME = namealloc(&(seg->NAME)[5]);

	/* first : 
	   tie the non power tracks. with a best fit choice.
	   I guess it's better than a first fit, but nothing ensures that! */
	for (pt = link; pt; pt = pt->NEXT) {
		if (!pt->DATA || !pt->TYPE)
			continue;
#if 0
		if (isvdd(((phseg_list *)pt->DATA)->NAME) ||
				isvss(((phseg_list *)pt->DATA)->NAME)) {
			n++; /* n is the number of powers */
			continue;
		}
#endif
		/* make the choice :
		   j is the width indicator for the current loop.
		   width is the closest available width for the overall supply.
		   track is the number of the center of the wire to be drawn. */
		j = 0;
		width = (ch->XAB2 - ch->XAB1) / SCALE_X;
		track = -1;
		for (i = 0; i <= (ch->XAB2 - ch->XAB1) / SCALE_X; i++) {
			if (freetracks[i]) {
				if (j >= ((phseg_list *)pt->DATA)->WIDTH / SCALE_X) {
					if (j < width) {
						track = i - j / 2; /* center of the track */
						width = j;
					}
				}
				j = 0;
			} else
				j++;
		}
		if (track == -1) {
			error(WARNING, NOTRACK);
			return;
		}
		/* draw the wire :
		   I've got a track in use, so I first modify the list of free tracks.
		   And then, I draw the needed wire.
		   Note that here the real wire width is used, in order to preserve
		   as mamy free tracks as possible for later use. */
		width = ((phseg_list *)pt->DATA)->WIDTH / SCALE_X; 
		for (i = track - width / 2 - width % 2;
				i <= track + width / 2 + width % 2; i++)
			freetracks[i] = '\1';
		for (i = 1; i < (AL_AL - 1); i++) { /* the -1 is for border adjustment */
			if (track - width / 2 - width % 2 - i >= 0)
				freetracks[track - width / 2 - width % 2 - i] = '\1';
			if (track + width / 2 + width % 2 + i
					<= (ch->XAB2 - ch->XAB1) / SCALE_X)
				freetracks[track + width / 2 + width % 2 + i] = '\1';
		}
		addphseg(ch, ALU1,
					((phseg_list *)pt->DATA)->WIDTH,
					ch->XAB1 + (track * SCALE_X), 
					((phseg_list *)pt->DATA)->Y1,
					ch->XAB1 + (track * SCALE_X), 
					((phseg_list *)pt->TYPE)->Y1,
					((phseg_list *)pt->DATA)->NAME);
		bigvia(ch, CONT_VIA,
					ch->XAB1 + (track * SCALE_X), 
					((phseg_list *)pt->DATA)->Y1,
					((phseg_list *)pt->DATA)->WIDTH,
					((phseg_list *)pt->DATA)->WIDTH);
		bigvia(ch, CONT_VIA,
					ch->XAB1 + (track * SCALE_X), 
					((phseg_list *)pt->TYPE)->Y1,
					((phseg_list *)pt->DATA)->WIDTH,
					((phseg_list *)pt->DATA)->WIDTH);
	}
	freeptype(link);
#ifdef SCRDEBUG
	/* debug :
	   poly wires are drawn where I guess I've the right to go. */
	for (i = 0; i <= (ch->XAB2 - ch->XAB1) / SCALE_X; i++) {
		if (freetracks[i])
			continue;
		addphseg(ch, POLY, 1 * SCALE_X,
					ch->XAB1 + (i * SCALE_X), ch->YAB1,
					ch->XAB1 + (i * SCALE_X), ch->YAB2, "trou_sans_fin");
	}
	savephfig(ch);
#endif
}
