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

#ifdef pc
#undef pc
#endif
#include <stdio.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"

channel_list *CHANNELS;

/*******************************************************************************
* Basical functions to allocate appropriate objects for preparation to a       *
* call to the router                                                           *
*******************************************************************************/
channel_list *
	addchannel(channels, channelName, net, supplies, direction, coordinate)
channel_list *channels;
char *channelName;
bnet_list *net;
bnet_list *supplies;
char direction;
long coordinate;
{
channel_list *c;

	c = (channel_list *)mbkalloc(sizeof(channel_list));
	c->NAME = namealloc(channelName);
	c->DIRECTION = direction;
	c->COORDINATE = coordinate;
	c->NETS = net;
	c->SUPPLIES = supplies;
	c->NEXT = channels;
	return c;
}

bnet_list *
	addnet(nets, netName, point)
bnet_list *nets;
char *netName;
pt_list *point;
{
bnet_list *n;

	n = (bnet_list *)mbkalloc(sizeof(bnet_list));
	n->NAME = namealloc(netName);
	n->POINTS = point;
	n->NEXT = nets;
	return n;
}

pt_list *
	addpoint(points, pointName, x, y, face, mbk, scr)
pt_list *points;
char *pointName;
long x, y;
char face;
phcon_list *mbk;
ConnectorList *scr;
{
pt_list *p;

	p = (pt_list *)mbkalloc(sizeof(pt_list));
	p->NAME = namealloc(pointName);
	p->X = x;
	p->Y = y;
	p->FACE = face;
	p->MBK = mbk;
	p->SCR = scr;
	p->NEXT = points;
	return p;
}

/*******************************************************************************
* this return the name given by the user to a signal that has been routed by   *
* the symbolic router                                                          *
*******************************************************************************/
char *
	getnetname(channel, s)
channel_list *channel;
char *s;
{
bnet_list *net;
int i, si; /*si is signalindex*/

	si = atoi(s + 4);
	for (i = 1, net = channel->NETS; net; net = net->NEXT, i++)
		if (i == si)
			return net->NAME;
	return "????";
}

/*******************************************************************************
* this function compute the values to be added to the channel abutment box to  *
* ensure no violation on design rules while routing.                           *
*******************************************************************************/
void
	bboxshift(flop, shiftN, shiftS)
phfig_list *flop;
long *shiftN, *shiftS;
{
phins_list *up, *down, *pi;
ptype_list *pup, *pdown;
phcon_list *pc;
phfig_list *pf;
long xcon, ycon, dx, x, y, xx, yy;
char sym;

	up = flop->PHINS;
	pup = getptype(up->USER, (long)PLACEABOX);
	if (pup == NULL) {
		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;
		}
	} else {
		x = ((num_list *)pup->DATA)->DATA;
		y = ((num_list *)pup->DATA)->NEXT->DATA;
	}
	down = flop->PHINS->NEXT;
	pdown = getptype(down->USER, (long)PLACEABOX);
	if (pdown == NULL) {
		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;
		}
	} else {
		xx = ((num_list *)pdown->DATA)->DATA;
		yy = ((num_list *)pdown->DATA)->NEXT->DATA;
	}
	if (yy == up->YINS)
		sym = HOR;
	else if (y == down->YINS) {
		sym = HOR;
		pi = down;
		down = up;
		up = pi;
		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;
		pi = down;
		down = up;
		up = pi;
		dx = xx;
		xx = x;
		x = dx;
	} else {
		fprintf(stderr, "Gag, the channel is lost in the intergalactic space\n");
		EXIT(1);
	}
	if (sym == HOR) {
		pf = getphfig(up->FIGNAME, 'P');
		/* y is in fact ymin for up :
		   it is initialized to the lowest possible value for a figure,
			its abutment box. */
		y = up->YINS;
		for (pc = pf->PHCON; pc; pc = pc->NEXT) {
			if (pc->LAYER != ALU1 && pc->LAYER != ALU2)
				continue;
			xyflat(&xcon, &ycon, pc->XCON, pc->YCON, up->XINS, up->YINS,
						pf->XAB1, pf->YAB1, pf->XAB2, pf->YAB2, up->TRANSF);
			switch (instanceface(pc->ORIENT, up->TRANSF)) {
				case WEST :
				case EAST :
					y = MIN(y, ycon - (pc->WIDTH / (2 * SCALE_X)) * SCALE_X);
					continue;
				default :
					continue;
			}
		}
		*shiftS = up->YINS - y;
		pf = getphfig(down->FIGNAME, 'P');
		/* y is in fact ymax for down :
		   it is initialized to the lowest possible value for a figure,
			its abutment box. */
		y = yy;
		for (pc = pf->PHCON; pc; pc = pc->NEXT) {
			if (pc->LAYER != ALU1 && pc->LAYER != ALU2)
				continue;
			xyflat(&xcon, &ycon, pc->XCON, pc->YCON, down->XINS, down->YINS,
						pf->XAB1, pf->YAB1, pf->XAB2, pf->YAB2, down->TRANSF);
			switch (instanceface(pc->ORIENT, down->TRANSF)) {
				case WEST :
				case EAST :
					y = MAX(y, ycon + (pc->WIDTH / (2 * SCALE_X)) * SCALE_X);
					continue;
				default :
					continue;
			}
		}
		*shiftN = y - yy;
	} else { /* vertical channel */
		pf = getphfig(up->FIGNAME, 'P'); /* left is up */
		/* xx is in fact xmax for up :
		   it is initialized to the lowest possible value for a figure,
			its abutment box. */
		xx = x;
		for (pc = pf->PHCON; pc; pc = pc->NEXT) {
			xyflat(&xcon, &ycon, pc->XCON, pc->YCON, up->XINS, up->YINS,
						pf->XAB1, pf->YAB1, pf->XAB2, pf->YAB2, up->TRANSF);
			switch (instanceface(pc->ORIENT, up->TRANSF)) {
				case SOUTH :
				case NORTH :
					xx = MAX(xx, xcon + (pc->WIDTH / (2 * SCALE_X)) * SCALE_X);
					continue;
				default :
					continue;
			}
		}
		*shiftS = xx - x;
		pf = getphfig(down->FIGNAME, 'P'); /* right is down */
		/* xx is in fact xmin for down :
		   it is initialized to the lowest possible value for a figure,
			its abutment box. */
		xx = down->XINS;
		for (pc = pf->PHCON; pc; pc = pc->NEXT) {
			xyflat(&xcon, &ycon, pc->XCON, pc->YCON, down->XINS, down->YINS,
						pf->XAB1, pf->YAB1, pf->XAB2, pf->YAB2, down->TRANSF);
			switch (instanceface(pc->ORIENT, down->TRANSF)) {
				case SOUTH :
				case NORTH :
					xx = MIN(xx, xcon - (pc->WIDTH / (2 * SCALE_X)) * SCALE_X);
					continue;
				default :
					continue;
			}
		}
		*shiftN = down->XINS - xx;
	}
}

/*******************************************************************************
* this function translates the result of the symbolic channel router into the  *
* off grid layout that is to be used really.                                   *
*******************************************************************************/
void
	scrtombk(model, channel, sh, sv, v1, cw, ch, headG, headN, headS, flagN, flagS, shiftN, shiftS)
phfig_list *model;
channel_list *channel;
SegmentList *sh, *sv;
ViasList *v1;
long cw, ch;
ptype_list *headG, *headN, *headS;
int flagS, flagN;
long shiftS, shiftN;
{
SegmentList *s;
ViasList *v;
phseg_list *sg;
phcon_list *cn;
phfig_list *f;
ptype_list *p1, *p2, *p3;
long xaux, x1, x2, y, dy, ny, scw = cw + 1;
long localtrack; /* `local` number of tracks for a shift */
long trackN = 0, trackS = 0; /* global tracks used for the shift */
long layerN = 0, layerS = 0; /* tracks for the layer conversion if needed */
long suppliesN = 0, suppliesS = 0; /* tracks needed for supplies */
long flagNT = flagN, flagST = flagS; /* temporary flags for layer change */
chain_list *deported, *c;
char *str;
bnet_list *power;
pt_list *pt;

	f = addphfig(channel->NAME);
	/* translation :
	   scr data structure to mbk, using the coordinates of the predefined grid
	   as segments coordinates. This ensures a respect of the design rules.
	   No alignment is done, this is a straight forward operation that uses
	   only the predefined grid. */

	/* retrive the end of the symbolic channel for its coordinate */
	for (p3 = headG; p3->NEXT; p3 = p3->NEXT);
	
	for (s = sh; s; s = s->NextSeg) {
		if (s->X1Seg == 0) {
			if (channel->DIRECTION == HOR)
				x1 = model->XAB1;
			else
				x1 = model->YAB1;
		} else {
			for (p2 = NULL, p1 = headG; p1; p1 = p1->NEXT) {
				if (s->X1Seg == p1->TYPE)
					break;
				p2 = p1;
			}
			if (p1 != NULL)
				x1 = ((pt_list *)p1->DATA)->X;
			else /* p2 points on the last known channel object */
				x1 = ((pt_list *)p2->DATA)->X +
							(s->X1Seg - p2->TYPE) * PITCH * SCALE_X;
		}

		/* abjust right connectors :
		   the symbolic channel router algoritm may go over the limit of the
		   channel given when calling it.
		   care must be taken to ensure correct right hand side alignment. */
		if (s->X2Seg == scw) {
			if (channel->DIRECTION == HOR) {
				xaux = model->XAB2;
				x2 = ((pt_list *)p3->DATA)->X + (scw - p3->TYPE) * PITCH * SCALE_X;
				x2 = MAX(x2, xaux);
			} else {
				xaux = model->YAB2;
				x2 = ((pt_list *)p3->DATA)->X + (scw - p3->TYPE) * PITCH * SCALE_X;
				x2 = MAX(x2, xaux);
			}
		} else {
			for (p2 = NULL, p1 = headG; p1; p1 = p1->NEXT) {
				if (s->X2Seg == p1->TYPE)
					break;
				p2 = p1;
			}
			if (p1 != NULL)
				x2 = ((pt_list *)p1->DATA)->X;
			else
				x2 = ((pt_list *)p2->DATA)->X +
						(s->X2Seg - p2->TYPE) * PITCH * SCALE_X;
		}
		cw = MAX(cw, MAX(x1, x2));
		addphseg(f, ALU2, 2 * SCALE_X, x1, s->Y1Seg * PITCH * SCALE_X,
					x2, s->Y2Seg * PITCH * SCALE_X, getnetname(channel, s->SegName));
	}

	for (s = sv; s; s = s->NextSeg) {
		for (p2 = NULL, p1 = headG; p1; p1 = p1->NEXT) {
			if (s->X1Seg == p1->TYPE)
				break;
			p2 = p1;
		}
		if (p1 != NULL)
			x1 = ((pt_list *)p1->DATA)->X;
		else
			x1 = ((pt_list *)p2->DATA)->X +
					(s->X1Seg - p2->TYPE) * PITCH * SCALE_X;
		cw = MAX(cw, x1);
		addphseg(f, ALU1, 1 *SCALE_X, x1, s->Y1Seg * PITCH * SCALE_X,
					x1, s->Y2Seg * PITCH * SCALE_X, getnetname(channel, s->SegName));
	}

	for (v = v1; v; v = v->NextVia) {
		for (p2 = NULL, p1 = headG; p1; p1 = p1->NEXT) {
			if (v->XVia == p1->TYPE)
				break;
			p2 = p1;
		}
		if (p1 != NULL)
			x1 = ((pt_list *)p1->DATA)->X;
		else if (p2 != NULL)
			x1 = ((pt_list *)p2->DATA)->X +
					(v->XVia - p2->TYPE) * PITCH * SCALE_X;
		cw = MAX(cw, x1);
		addphvia(f, CONT_VIA, x1, v->YVia * PITCH * SCALE_X);
	}

	/* are supplies track needed :
	   we check for the existence of supplies tracks on both sides of the
	   channel.
		The building algorithm garanties that face are either NORTH or SOUTH. */
	for (power = channel->SUPPLIES; power; power = power->NEXT)
		for (pt = power->POINTS; pt; pt = pt->NEXT)
			if (pt->FACE == NORTH) {
				suppliesN += (long)pt->SCR + AL_AL;
				flagN = 1; /* we shall create shift anyway */
				break;
			}
	for (power = channel->SUPPLIES; power; power = power->NEXT)
		for (pt = power->POINTS; pt; pt = pt->NEXT)
			if (pt->FACE == SOUTH) {
				suppliesS += (long)pt->SCR + AL_AL;
				flagS = 1; /* we shall create shift anyway */
				break;
			}
	if (suppliesN) {
		suppliesN -= AL_AL;
		suppliesN *= SCALE_X;
	}
	if (suppliesS) {
		suppliesS -= AL_AL;
		suppliesS *= SCALE_X;
	}
	/* some more shifts :
	   due to an under estimated abutment box, and directly added to
	   supplies, since they have the same effects.
		Here, we assume, (we may check later if needed), that the maximun
		width of a connector is smaller than the deports. */
	if (shiftN && !flagN) {
		suppliesN += shiftN - AL_AL * SCALE_X;
		flagN = 1;
	}
	if (shiftS && !flagS) {
		suppliesS += shiftS - AL_AL * SCALE_X;
		flagS = 1;
	}

	/* shift bulding :
	   since connectors are not on the grid, elbows are to be drawn to connect
	   the instance connector to the scr result.
	   this is done in two phases, first of all the 'logical' shifts are done
	   while verifiing 'locally' the design rules, then the biggest of all shifts
	   is used to stretch the smaller ones to appropriate dimensions. */
	/* order of creation :
	   the coordinates of all lists are supposed to be in decreasing order.
	   the algorithm will not work if this is not respected. */
	headG = (ptype_list *)reverse((chain_list *)headG);	
	if (flagS) {
		p2 = headG;
		xaux = LONG_MAX;
		trackS = 1;
		deported = NULL;
		for (p1 = headS; p1 != NULL; p1 = p1->NEXT) {
			if (headG->TYPE < p1->TYPE)
				x2 = ((pt_list *)headG->DATA)->X +
								(p1->TYPE - headG->TYPE) * PITCH * SCALE_X;
			else {
				while (p2 && p2->TYPE > p1->TYPE)
					p2 = p2->NEXT;
				if (p2)
					x2 = ((pt_list *)p2->DATA)->X;
			}

			if (xaux == LONG_MAX)
				localtrack = 1;
			else if (xaux - x2 < AL_AL * SCALE_X) {
					localtrack++;
					trackS = MAX(localtrack, trackS);
			} else
				localtrack = 1;
			x1 = ((pt_list *)p1->DATA)->X;
			xaux = x1;
			deported = addchain(deported,
							(void *)addphseg(f, ALU1, 1 * SCALE_X,
											x1, 0, x2, 0,
											((pt_list *)p1->DATA)->NAME));
			if (((pt_list *)p1->DATA)->MBK->LAYER == ALU1 || suppliesS) {
				deported = addchain(deported,
									(void *)addphseg(f, ALU1, 1 * SCALE_X,
										x1,
										0,
										x1,
										-(localtrack - 1) * AL_AL * SCALE_X - suppliesS,
										((pt_list *)p1->DATA)->NAME));
				deported = addchain(deported,
									(void *)addphseg(f, ALU1, 1 * SCALE_X,
										x1,
										-(localtrack - 1) * AL_AL * SCALE_X - suppliesS,
										x1,
										-localtrack * AL_AL * SCALE_X - suppliesS,
										((pt_list *)p1->DATA)->NAME));
			} else {
				deported = addchain(deported,
									(void *)addphseg(f, ALU1, 1 * SCALE_X,
										x1,
										0,
										x1,
										-(localtrack - 1) * AL_AL * SCALE_X - suppliesS,
										((pt_list *)p1->DATA)->NAME));
				deported = addchain(deported,
									(void *)addphseg(f, ALU2, 2 * SCALE_X,
										x1,
										-(localtrack - 1) * AL_AL * SCALE_X - suppliesS,
										x1,
										-localtrack * AL_AL * SCALE_X - suppliesS,
										((pt_list *)p1->DATA)->NAME));
			}
		}
		/* do the shift on the mbk segments :
		   knowing the minimum y coordinate, adjusts to it all segments, and
		   add some more when needed. */
		y = -trackS * AL_AL * SCALE_X - suppliesS;
		for (c = deported; c; c = c->NEXT) {
			if ((dy = ((phseg_list *)c->DATA)->Y1 - y) > 0) { /* dy is >= 0 */
				/* this is the vertical segment */
				((phseg_list *)c->DATA)->Y1 -= dy;
				((phseg_list *)c->DATA)->Y2 -= dy;
				/* if changing layer is to be done, we must put a via */
				if (((phseg_list *)c->DATA)->LAYER == ALU2 && !suppliesS) {
					(void)addphvia(f, CONT_VIA,
										((phseg_list *)c->DATA)->X1,
										((phseg_list *)c->DATA)->Y2);
					/* and avoid notches */
					if (((phseg_list *)c->NEXT->DATA)->Y2 -
							((phseg_list *)c->NEXT->DATA)->Y1 < AL_AL * SCALE_X)
						((phseg_list *)c->NEXT->NEXT->DATA)->WIDTH = 2 * SCALE_X;
				}
				c = c->NEXT;
				((phseg_list *)c->DATA)->Y1 -= dy;
				((phseg_list *)c->DATA)->Y2 -= dy;
				c = c->NEXT;
				/* this is the horizontal one */
				((phseg_list *)c->DATA)->Y1 -= dy;
				((phseg_list *)c->DATA)->Y2 -= dy;
				str = ((phseg_list *)c->DATA)->NAME;
				/* we shall create the last one */
				(void)addphseg(f, ALU1, 1 * SCALE_X,
										((phseg_list *)c->DATA)->X2, 0,
										((phseg_list *)c->DATA)->X2,
										((phseg_list *)c->DATA)->Y2, str);
			} else {
				/* if changing layer is to be done */
				if (((phseg_list *)c->DATA)->LAYER == ALU2 && !suppliesS)
					(void)addphvia(f, CONT_VIA,
										((phseg_list *)c->DATA)->X1,
										((phseg_list *)c->DATA)->Y2);
				/* two segments must be skipped anyway */
				c = c->NEXT;
				c = c->NEXT;
			}
		}
		freechain(deported);
	}
	if (suppliesS)
		flagS = 0;

	if (flagN) {
		p2 = headG;
		xaux = LONG_MAX;
		trackN = 1;
		deported = NULL;
		for (p1 = headN; p1 != NULL; p1 = p1->NEXT) {
			if (headG->TYPE < p1->TYPE)
				x2 = ((pt_list *)headG->DATA)->X +
								(p1->TYPE - headG->TYPE) * PITCH * SCALE_X;
			else {
				while (p2 && p2->TYPE > p1->TYPE)
					p2 = p2->NEXT;
				if (p2)
					x2 = ((pt_list *)p2->DATA)->X;
			}
			if (xaux == LONG_MAX)
				localtrack = 1;
			else if (xaux - x2 < AL_AL * SCALE_X) {
					localtrack++;
					trackN = MAX(localtrack, trackN);
			} else
				localtrack = 1;
			x1 = ((pt_list *)p1->DATA)->X;
			xaux = x1;
			y = (ch + 1) * PITCH * SCALE_X;
			deported = addchain(deported,
							(void *)addphseg(f, ALU1, 1 * SCALE_X,
											x1, y, x2, y, ((pt_list *)p1->DATA)->NAME));
			/* avoid drc error :
			   if an alu2 wire is drawn all the way to the crossing alu1 wire,
			   a drc error may occur if, and lony if, a notch is detected and
			   thus a two lambda alu1 wire is drawn.
			   So checks are done, and wire broken. */
			if (((pt_list *)p1->DATA)->MBK->LAYER == ALU1 || suppliesN) {
				deported = addchain(deported,
								(void *)addphseg(f, ALU1, 1 * SCALE_X,
									x1,
									y,
									x1,
									y + (localtrack - 1) * AL_AL * SCALE_X + suppliesN,
									((pt_list *)p1->DATA)->NAME));
				deported = addchain(deported,
								(void *)addphseg(f, ALU1, 1 * SCALE_X,
									x1,
									y + (localtrack - 1) * AL_AL * SCALE_X + suppliesN,
									x1,
									y + localtrack * AL_AL * SCALE_X + suppliesN,
									((pt_list *)p1->DATA)->NAME));
			} else {
				deported = addchain(deported,
								(void *)addphseg(f, ALU1, 1 * SCALE_X,
									x1,
									y,
									x1,
									y + (localtrack - 1) * AL_AL * SCALE_X + suppliesN,
									((pt_list *)p1->DATA)->NAME));
				deported = addchain(deported,
								(void *)addphseg(f, ALU2, 2 * SCALE_X,
									x1,
									y + (localtrack - 1) * AL_AL * SCALE_X + suppliesN,
									x1,
									y + localtrack * AL_AL * SCALE_X + suppliesN,
									((pt_list *)p1->DATA)->NAME));
			}
		}
		/* do the shift on the mbk segments :
		   knowing the minimum y coordinate, adjusts to it all segments, and
		   add some more when needed. */
		y += trackN * AL_AL * SCALE_X + suppliesN;
		for (c = deported; c; c = c->NEXT) {
			if ((dy = y - ((phseg_list *)c->DATA)->Y2) >= 0) { /* dy is >= 0 */
				/* this is the vertical segment */
				((phseg_list *)c->DATA)->Y1 += dy;
				((phseg_list *)c->DATA)->Y2 += dy;
				/* if changing layer is to be done */
				if (((phseg_list *)c->DATA)->LAYER == ALU2 && !suppliesN) {
					(void)addphvia(f, CONT_VIA,
										((phseg_list *)c->DATA)->X1,
										((phseg_list *)c->DATA)->Y1);
					/* and avoid notches */
					if (((phseg_list *)c->NEXT->DATA)->Y2 -
							((phseg_list *)c->NEXT->DATA)->Y1 < AL_AL * SCALE_X)
						((phseg_list *)c->NEXT->NEXT->DATA)->WIDTH = 2 * SCALE_X;
				}
				c = c->NEXT;
				ny = ((phseg_list *)c->DATA)->Y1;
				((phseg_list *)c->DATA)->Y1 += dy;
				((phseg_list *)c->DATA)->Y2 += dy;
				c = c->NEXT;
				/* this is the horizontal one */
				((phseg_list *)c->DATA)->Y1 += dy;
				((phseg_list *)c->DATA)->Y2 += dy;
				str = ((phseg_list *)c->DATA)->NAME;
				/* we shall create the last one */
				(void)addphseg(f, ALU1, 1 * SCALE_X,
										((phseg_list *)c->DATA)->X2, ny,
										((phseg_list *)c->DATA)->X2,
										((phseg_list *)c->DATA)->Y1, str);
			} else {
				/* if changing layer is to be done */
				if (((phseg_list *)c->DATA)->LAYER == ALU2 && !suppliesN)
					(void)addphvia(f, CONT_VIA,
										((phseg_list *)c->DATA)->X1,
										((phseg_list *)c->DATA)->Y1);
				/* two segments must be skipped anyway */
				c = c->NEXT;
				c = c->NEXT;
			}
		}
		freechain(deported);
	}
	if (suppliesN)
		flagN = 0;

	/* layer conversion :
	   if layers on connectors are not routing prefered layer, for the vertical
	   direction, then I must used one more pitch for changing them.
		This must be done also if power lines are needed, so it must be checked
		right here. */
	if (!flagN) {
		for (p1 = headN; p1 != NULL; p1 = p1->NEXT)
			if (((pt_list *)p1->DATA)->MBK->LAYER != ALU1)
				break;
		/* changing layers because of power lines :
		   switching may occur if there is more than one line on with north
		   points on it, or if a line has ALU1 points on it. */
		if (!p1) {
			if (suppliesN) {
				x1 = x2 = 0;
				for (power = channel->SUPPLIES; power; power = power->NEXT) {
					for (pt = power->POINTS; pt; pt = pt->NEXT)
						if (pt->FACE == NORTH && pt->MBK->LAYER == ALU1)
							x1++;
					if (x1)
						x2++;
					x2++;
				}
				if (x2 > 1)
					p1 = (ptype_list *)1;
			}
		}
		if (p1) {
			/* other shifts :
			   if a change of layer is needed on the border of the channel,
			   an ALU1 wire a pitch long must be drawn in any case. */
			suppliesN += AL_AL * SCALE_X;
			y = (ch + 1) * PITCH * SCALE_X + trackN * AL_AL * SCALE_X + suppliesN;
			layerN = 1;
			for (p1 = headN; p1 != NULL; p1 = p1->NEXT) {
				if (((pt_list *)p1->DATA)->MBK->LAYER == ALU1)
					addphseg(f, ALU1, 1 * SCALE_X, ((pt_list *)p1->DATA)->X,
								y - AL_AL * SCALE_X,
								((pt_list *)p1->DATA)->X, y + layerN * PITCH * SCALE_X,
								((pt_list *)p1->DATA)->NAME);
				else {
					addphseg(f, ALU2, 2 * SCALE_X, ((pt_list *)p1->DATA)->X, y,
								((pt_list *)p1->DATA)->X,
								y + layerN * PITCH * SCALE_X,
								((pt_list *)p1->DATA)->NAME);
					addphvia(f, CONT_VIA,
								((pt_list *)p1->DATA)->X, y);
					addphseg(f, ALU1, 1 * SCALE_X, ((pt_list *)p1->DATA)->X, y,
								((pt_list *)p1->DATA)->X,
								y - AL_AL * SCALE_X,
								((pt_list *)p1->DATA)->NAME);
				}
			}
		}
	}

	if (!flagS) {
		for (p1 = headS; p1 != NULL; p1 = p1->NEXT)
			if (((pt_list *)p1->DATA)->MBK->LAYER != ALU1)
				break;
		/* changing layers because of power lines :
		   switching may occur if there is more than one line on with north
		   points on it, or if a line has ALU1 points on it. */
		if (!p1) {
			if (suppliesS) {
				x1 = x2 = 0;
				for (power = channel->SUPPLIES; power; power = power->NEXT) {
					for (pt = power->POINTS; pt; pt = pt->NEXT)
						if (pt->FACE == SOUTH && pt->MBK->LAYER == ALU1)
							x1++;
					if (x1)
						x2++;
					x2++;
				}
				if (x2 > 1)
					p1 = (ptype_list *)1;
			}
		}
		if (p1) {
			/* other shifts :
			   if a change of layer is needed on the border of the channel. */
			suppliesS += AL_AL * SCALE_X;
			y = -trackS * AL_AL * SCALE_X - suppliesS;
			layerS = 1;
			for (p1 = headS; p1 != NULL; p1 = p1->NEXT) {
				if (((pt_list *)p1->DATA)->MBK->LAYER == ALU1)
					addphseg(f, ALU1, 1 * SCALE_X, ((pt_list *)p1->DATA)->X,
								y + AL_AL * SCALE_X,
								((pt_list *)p1->DATA)->X, y - layerS * PITCH * SCALE_X,
								((pt_list *)p1->DATA)->NAME);
				else {
					addphseg(f, ALU2, 2 * SCALE_X, ((pt_list *)p1->DATA)->X, y,
								((pt_list *)p1->DATA)->X, y - layerS * PITCH * SCALE_X,
								((pt_list *)p1->DATA)->NAME);
					addphvia(f, CONT_VIA,
								((pt_list *)p1->DATA)->X, y);
					addphseg(f, ALU1, 1 * SCALE_X, ((pt_list *)p1->DATA)->X,
								y + AL_AL * SCALE_X,
								((pt_list *)p1->DATA)->X, y,
								((pt_list *)p1->DATA)->NAME);
				}
			}
		}
	}

	if (channel->DIRECTION == HOR) {
		x1 = model->XAB1;
		x2 = model->XAB2;
	} else {
		x1 = model->YAB1;
		x2 = model->YAB2;
	}
	/* cw :
	   cw is not the exact channel width, but the channel width + x1.
	   Keep that in mind! */
	defab(f, x1,
				-trackS * AL_AL * SCALE_X - layerS * PITCH * SCALE_X - suppliesS,
				cw = MAX(cw, x2),
				(ch + 1) * PITCH * SCALE_X + trackN * AL_AL * SCALE_X +
						layerN * PITCH * SCALE_X + suppliesN);

	/* power lines :
	   the lines are to be drawn now using the width given by the user.
	   we do north, then south. */
	/* f was model at once */
	if (suppliesN || suppliesS) {
		if (channel->DIRECTION == HOR) {
			x1 = model->XAB1;
			x2 = MAX(model->XAB2, cw);
			/* xaux = model->XAB2;
			x2 = ((pt_list *)p3->DATA)->X + (scw - p3->TYPE) * PITCH * SCALE_X;
			*/
		} else {
			x1 = model->YAB1;
			x2 = MAX(model->YAB2, cw);
         /*
			xaux = model->YAB2;
			x2 = ((pt_list *)p3->DATA)->X + (scw - p3->TYPE) * PITCH * SCALE_X;
         */
		}
	}

   /* DELTA:
      is needed because if power rails are drawn in metal 2 at minimum 
      symbolic edge to edge distance, then metal 1 bridges with same
      dimensions will provide nice drc errors, since metal2-metal2 is 2
      metal1-metal1 is 2.5 */
  
#define DELTA 1

	if (suppliesN) {
		y = (ch + 1) * PITCH * SCALE_X + trackN * AL_AL * SCALE_X - shiftN;
		for (power = channel->SUPPLIES; power; power = power->NEXT) {
			/* is a power track needed ?
			   here we check for the presence of at least one connector on the
			   north face, to know if it's necessary to draw a power line. */
			for (pt = power->POINTS; pt; pt = pt->NEXT)
				if (pt->FACE == NORTH)
					break;
			if (!pt)
				continue;
			dy = ((long)power->POINTS->SCR + AL_AL) / 2;
			/* center of the wire */
			y += dy * SCALE_X;
			addphseg(f, ALU2, (long)(power->POINTS->SCR) * SCALE_X,
							x1, y, x2, y, power->NAME);
			cn = addphcon(f, EAST, power->NAME, /* x2 */ cw, y, ALU2,
							(long)(power->POINTS->SCR) * SCALE_X);
			cn->USER = addptype(cn->USER, FLOPCOORD, power->NAME);
			cn = addphcon(f, WEST, power->NAME, x1, y, ALU2,
							(long)(power->POINTS->SCR) * SCALE_X);
			cn->USER = addptype(cn->USER, FLOPCOORD, power->NAME);
			/* first line :
			   no bridges are needed for ALU2 points. */
			if (power->NEXT == NULL) {
				for (pt = power->POINTS; pt; pt = pt->NEXT) {
					if (pt->FACE == NORTH) {
						if (pt->MBK->LAYER == ALU1) {
							addphseg(f, ALU1, (pt->Y - DELTA) * SCALE_X,
											pt->X, y, pt->X, f->YAB2,
											power->NAME);
							/* not a bridge, a connexion */
							bigvia(f, CONT_VIA, pt->X, y,
										pt->Y * SCALE_X + 1 * SCALE_X,
										(long)(power->POINTS->SCR) * SCALE_X);
						} else
							addphseg(f, ALU2, pt->Y * SCALE_X,
											pt->X, y, pt->X, f->YAB2,
											power->NAME);
					}
				}
			} else {
				for (pt = power->POINTS; pt; pt = pt->NEXT) {
					if (pt->FACE == NORTH) {
						if (pt->MBK->LAYER == ALU1) {
							addphseg(f, ALU1, (pt->Y - DELTA) * SCALE_X,
											pt->X, y, pt->X, f->YAB2,
											power->NAME);
							/* is this a bridge ? */
							bigvia(f, CONT_VIA,
										pt->X, y, pt->Y * SCALE_X + 1 * SCALE_X,
										(long)(power->POINTS->SCR) * SCALE_X);
						} else {
							addphseg(f, ALU2, pt->Y * SCALE_X,
											pt->X, f->YAB2 - PITCH * SCALE_X,
											pt->X, f->YAB2,
											power->NAME);
							/* brigde */
							bigvia(f, CONT_VIA, pt->X, f->YAB2 - PITCH * SCALE_X,
										pt->Y * SCALE_X + 1 * SCALE_X, 0);
							addphseg(f, ALU1, (pt->Y - DELTA) * SCALE_X,
											pt->X, y, pt->X, f->YAB2 - PITCH * SCALE_X,
											power->NAME);
							bigvia(f, CONT_VIA, pt->X, y,
										pt->Y * SCALE_X + 1 * SCALE_X,
										(long)(power->POINTS->SCR) * SCALE_X);
						}
					}
				}
			}
			/* move to next free pitch */
			y += dy * SCALE_X;
		}
	}

	if (suppliesS) {
		y = -trackS * AL_AL * SCALE_X + shiftS;
		for (power = channel->SUPPLIES; power; power = power->NEXT) {
			/* is a power tack needed ?
			   here we check for the presence of at least one connector on the
			   north face, to know if it's necessary to draw a power line. */
			for (pt = power->POINTS; pt; pt = pt->NEXT)
				if (pt->FACE == SOUTH)
					break;
			if (!pt)
				continue;
			dy = ((long)power->POINTS->SCR + AL_AL) / 2;
			y -= dy * SCALE_X;
			addphseg(f, ALU2, (long)(power->POINTS->SCR) * SCALE_X,
							x1, y, x2, y, power->NAME);
			cn = addphcon(f, EAST, power->NAME, /* x2 */ cw, y, ALU2,
							(long)(power->POINTS->SCR) * SCALE_X);
			cn->USER = addptype(cn->USER, FLOPCOORD, power->NAME);
			cn = addphcon(f, WEST, power->NAME, x1, y, ALU2,
							(long)(power->POINTS->SCR) * SCALE_X);
			cn->USER = addptype(cn->USER, FLOPCOORD, power->NAME);
			/* first line :
			   no bridges are needed for ALU2 points. */
			if (power->NEXT == NULL) {
				for (pt = power->POINTS; pt; pt = pt->NEXT) {
					if (pt->FACE == SOUTH) {
						if (pt->MBK->LAYER == ALU1) {
							addphseg(f, ALU1, (pt->Y - DELTA) * SCALE_X,
											pt->X, y, pt->X, f->YAB1,
											power->NAME);
							/* not a bridge, a connexion */
							bigvia(f, CONT_VIA, pt->X, y,
										pt->Y * SCALE_X + 1 * SCALE_X,
										(long)(power->POINTS->SCR) * SCALE_X);
						} else
							addphseg(f, ALU2, pt->Y * SCALE_X,
											pt->X, y, pt->X, f->YAB1,
											power->NAME);
					}
				}
			} else {
				for (pt = power->POINTS; pt; pt = pt->NEXT) {
					if (pt->FACE == SOUTH) {
						if (pt->MBK->LAYER == ALU1) {
							addphseg(f, ALU1, (pt->Y - DELTA) * SCALE_X,
											pt->X, y, pt->X, f->YAB1,
											power->NAME);
							/* bridge ? */
							bigvia(f, CONT_VIA, pt->X, y,
										pt->Y * SCALE_X + 1 * SCALE_X,
										(long)(power->POINTS->SCR) * SCALE_X);
						} else {
							addphseg(f, ALU2, pt->Y * SCALE_X,
											pt->X, f->YAB1 + PITCH *SCALE_X, pt->X,
											f->YAB1,
											power->NAME);
							/* bridges */
							bigvia(f, CONT_VIA, pt->X, f->YAB1 + PITCH * SCALE_X,
										pt->Y * SCALE_X + 1 * SCALE_X, 0);
							addphseg(f, ALU1, (pt->Y - DELTA) * SCALE_X,
											pt->X, y, pt->X, f->YAB1 + PITCH * SCALE_X,
											power->NAME);
							bigvia(f, CONT_VIA, pt->X, y,
										pt->Y * SCALE_X + 1 * SCALE_X,
										(long)(power->POINTS->SCR) * SCALE_X);
						}
					}
				}
			}
			y -= dy * SCALE_X;
		}
	}
#ifdef SCRDEBUG
	savephfig(f);
#endif
}

/* standard, time consuming, sorting procedure for ptypes */
ptype_list *
	sort_ptype(ptype)
ptype_list *ptype;
{
ptype_list **previous, **scanprevious, *index, *swapindex, *scanindex;

	/* sort ptype by increasing type */
	previous = &ptype;
	for (index = ptype; index; index = index->NEXT) {
		scanprevious = &index;
		for (scanindex = index->NEXT; scanindex; scanindex = scanindex->NEXT) {
			if (scanindex->TYPE < index->TYPE) {
				*previous = scanindex;
				swapindex = scanindex->NEXT;
				if (scanindex != index->NEXT) {
					scanindex->NEXT = index->NEXT;
					*scanprevious = index;
				} else
					scanindex->NEXT = index;
				index->NEXT = swapindex;
				swapindex = scanindex;
				scanindex = index;
				index = swapindex;
			}
			scanprevious = &scanindex->NEXT;
		}
		previous = &index->NEXT;
	}
	return ptype;
}

/*a little time consuming, ain't it ? */
ConnectorList *
	addSCR(scrc, conname, mark, retptr)
ConnectorList *scrc, **retptr;
long	conname, mark;
{
ConnectorList *current;
ConnectorList *last = NULL;

	if (scrc != NULL)
		for (last = scrc; last->NextCon != NULL; last = last->NextCon);

	current = (ConnectorList *)mbkalloc(sizeof(ConnectorList));
	current->ConName = conname;
	current->Mark = mark;
	current->NextCon = NULL;
	if (last != NULL)
		last->NextCon = current;
	else
		scrc = current;
	*retptr = current;
	return scrc;
}

/* translate the output of the symbolic channel router into a fixed grid,
   standard cell like channel, for potential debug. */
void
	scrtopitched(channel, sh, sv, vl, cw, ch)
channel_list *channel;
SegmentList *sh, *sv;
ViasList	 *vl;
long cw, ch;
{
SegmentList *s;
ViasList	 *v;
phfig_list *f;

	f = addphfig("pitched");

	for (s = sh; s; s = s->NextSeg) {
		addphseg(f, ALU2, 2 * SCALE_X,
					s->X1Seg * PITCH * SCALE_X,
					s->Y1Seg * PITCH * SCALE_X,
					s->X2Seg * PITCH * SCALE_X,
					s->Y2Seg * PITCH * SCALE_X,
					getnetname(channel, s->SegName));
	}

	for (s = sv; s; s = s->NextSeg) {
		addphseg(f, ALU1, 1 * SCALE_X,
					s->X1Seg * PITCH * SCALE_X,
					s->Y1Seg * PITCH * SCALE_X,
					s->X2Seg * PITCH * SCALE_X,
					s->Y2Seg * PITCH * SCALE_X,
					getnetname(channel, s->SegName));
	}
		
	for (v = vl; v; v = v->NextVia) {
		addphvia(f, CONT_VIA,
					v->XVia * PITCH * SCALE_X,
					v->YVia * PITCH * SCALE_X);
	}
	cw ++, ch++;
	defab(f, 0, 0, cw * PITCH * SCALE_X, ch  * PITCH * SCALE_X);
	savephfig(f);
}

#ifdef SCRDEBUG
viewscr(s)
ConnectorList *s;
{
int i = 1;
ConnectorList *sp = s;

	(void)printf("{");
	while (s) {
		while (s->Mark > i++)
			if (i == 2)
				(void)printf("0"); 
			else
				(void)printf(", 0"); 
		if (i == 2)
			(void)printf("%d", s->ConName);
		else
			(void)printf(", %d", s->ConName);
		s = s->NextCon;
	}
	(void)printf("}\n");
}
#endif
