[comp.sources.unix] v18i017: Tree-structured data placer/router/plotter, Part03/03

rsalz@uunet.uu.net (Rich Salz) (03/14/89)

Submitted-by: Jim McBeath <voder!sci!gumby!jimmc>
Posting-number: Volume 18, Issue 17
Archive-name: treepar/part03

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 3)."
# Contents:  par.c
# Wrapped by rsalz@fig.bbn.com on Thu Mar  9 15:55:43 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'par.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'par.c'\"
else
echo shar: Extracting \"'par.c'\" \(26098 characters\)
sed "s/^X//" >'par.c' <<'END_OF_FILE'
X/* par.c - the actual placement and routine routines
X *
X * 12.Aug.87  jimmc  Initial definition - placement routines
X * 14.Aug.87  jimmc  More placement, routing routines
X *  3.Nov.87  jimmc  Add rowdir
X *  6.Nov.87  jimmc  Use XCALLOC macro
X * 18.Jan.88  jimmc  lint cleanup
X * 27.Jan.88  jimmc  Add feedthrough stuff
X * 29.Feb.88  jimmc  Improve robustness when doing partial place/routes
X */
X
X#include <ctype.h>
X#include "network.h"
X#include "xalloc.h"
X
X#define SPLITCHAR '#'
X
Xextern Nnet *NFindNet(), *NCreateNet();
Xextern Nbox *NFindBox(), *NCreateBox();
Xextern Nconn *NCreateConn();
Xextern NIFreeConn();
Xextern NClearNetConns(), NClearBoxConns();
Xextern NLinkConnNet();
X
Xextern char *index();
Xextern char *strsav();
X
Xextern Nbase *NCurBase;
Xextern char Tflag[];
X
X#define HROW (NCurBase->rowdir=='H')
X#define vX cc[HROW?0:1]
X#define vY cc[HROW?1:0]
X/* if rows are horizontal, vX is X and vY is Y */
X#define NorE (HROW?N:E)
X#define SorW (HROW?S:W)
X#define NorEstr (HROW?"N":"E")
X#define SorWstr (HROW?"S":"W")
X
Xextern int NPosConn();
Xextern Nbox *NFindBox();
X
Xstatic
XRUnmarkBox(box)
XNbox *box;
X{
X	box->parflags = 0;
X}
X
Xint
XRIsFeedBox(box)
XNbox *box;
X{
X	if (index(box->name,SPLITCHAR)) return 1;
X	return 0;
X}
X
Xstatic
XRUnSplitBox(box)
XNbox *box;
X{
Xextern int NUnLinkConnNet();
X
X	if (!index(box->name,SPLITCHAR)) return;
X	NDoGroup(&(box->connlist),NUnLinkConnNet);
X	NFreeGroup(&(box->connlist),NIFreeConn);
X}
X
Xstatic
XRFreeSplitBox(box)
XNbox *box;
X{
X	if (!index(box->name,SPLITCHAR)) return;
X	NIFreeBox(box);
X}
X
Xstatic
XRSelBox(box,rownum)
XNbox *box;
X{
Xint i;
X
X	if (box->parflags & ROWSET) return;
X	box->rownum = rownum;
X	box->parflags |= ROWSET;
X	for (i=0; i<box->connlist.count; i++) {
X		RSelBConn(box->connlist.d.conn[i],rownum);
X	}
X}
X
Xstatic
XRSelectBox(box)		/* set the row number in a box */
XNbox *box;
X{
X	RSelBox(box,0);		/* place this box in row 0 */
X}
X
Xstatic
XRUnsetrowBox(box)
XNbox *box;
X{
X	box->row = 0;
X}
X
Xstatic
XRSetrowBox(box)		/* set a box into a row */
XNbox *box;
X{
XNrow *row, *RFindRow();
X
X	if (box->row) return;	/* nop if already set */
X	row = RFindRow(NCurBase,box->rownum);
X	if (!row) {
X		printf("Can't find row %d for box %s\n",
X			box->rownum, box->name);
X		return;
X	}
X	box->row = row;
X	insertp(&(row->boxlist),(char *)box);
X}
X
Xstatic
XRSetrposBox(box)
XNbox *box;
X{
X	if (!box->row) return;
X	box->origin.vY = box->row->pos;
X}
X
Xstatic
XRClearOrderBox(box)
XNbox *box;
X{
X	box->parflags &= ~ORDERSET;
X}
X
Xstatic
XROrderCBox(box,side,negdir)
XNbox *box;
Xint side;
Xint negdir;
X{
XNgroup clist;
Xint i,j;
XNnet *net;
XNconn *cp;
Xint RCmpConn();
X
X	NClearGroup(&clist);
X	for (i=0; i<box->connlist.count; i++) {
X		/* collect all conns on the side of interest */
X		cp = box->connlist.d.conn[i];
X		if (cp->side==side && cp->net && cp->net->connlist.count>1) {
X			insertp(&clist,(char *)cp);
X		}
X	}
X	if (clist.count==0) return;
X	qsort((char *)clist.d.conn,clist.count,
X		sizeof(clist.d.conn[0]),RCmpConn);
X	for (i=0; i<clist.count; i++) {		/* see if any nets set yet */
X		net = clist.d.conn[i]->net;
X		if (net->parflags & ORDERSET) break;
X	}
X	if (i>=clist.count) {		/* no nets set yet */
X		if (negdir) i=clist.count;
X		else i=0;
X	}
X	for (j=i; j<clist.count; j++) {		/* count up from i */
X		ROrderNet(clist.d.conn[j]->net,0);
X	}
X	for (j=i-1; j>=0; j--) {		/* count down from i */
X		ROrderNet(clist.d.conn[j]->net,1);
X	}
X	if (clist.d.x) tfree((char *)clist.d.x);
X}
X
Xstatic
XROrderBox(box,negdir)	/* sets orders in neighboring boxes */
XNbox *box;
Xint negdir;		/* if set, expand in negative direction */
X{
X	if (box->parflags & ORDERSET) return;
X	box->parflags |= ORDERSET;
X	if (negdir)
X		box->rowpos = --(box->row->rowposmin);
X	else
X		box->rowpos = (box->row->rowposmax)++;
X	ROrderCBox(box,NorE,negdir);	/* order the north or east boxes */
X	ROrderCBox(box,SorW,negdir);	/* order the south or west boxes */
X}
X
Xstatic int
XRCmpBox(b1,b2)
XNbox **b1, **b2;
X{
X	return (*b1)->rowpos - (*b2)->rowpos;
X}
X
Xstatic
XRNetForceBox(box,side,pnforce,pncount)
XNbox *box;
Xint side;	/* use only connectors on this side */
Xint *pnforce;	/* return value - total net force */
Xint *pncount;	/* return value - count of nets */
X{
XNgroup clist;
Xint i;
Xint nforce, ncount;
Xint sumnforce, sumncount;
XNconn *cp, *conn;
XNnet *net;
X
X	NClearGroup(&clist);
X	for (i=0; i<box->connlist.count; i++) {
X		/* collect all conns on the side of interest */
X		cp = box->connlist.d.conn[i];
X		if (cp->side==side && cp->net && cp->net->connlist.count>1) {
X			insertp(&clist,(char *)cp);
X		}
X	}
X	sumnforce = 0;
X	sumncount = 0;
X	for (i=0; i<clist.count; i++) {
X		conn = clist.d.conn[i];
X		net = conn->net;
X		RNetForceNet(net,conn,&nforce,&ncount);
X		sumnforce += nforce;
X		sumncount += ncount;
X	}
X	if (clist.d.x) tfree((char *)clist.d.x);
X	*pnforce = sumnforce;
X	*pncount = sumncount;
X}
X
Xstatic
XRUnmarkNet(net)
XNnet *net;
X{
X	net->parflags = 0;		/* clear flag bits */
X}
X
Xstatic
XRSelNet(net,rownum)
XNnet *net;
Xint rownum;
X{
Xint i;
X
X	if (net->parflags & ROWSET) return;
X	net->rownum = rownum;
X	net->parflags |= ROWSET;
X	for (i=0; i<net->connlist.count; i++) {
X		RSelNConn(net->connlist.d.conn[i],rownum);
X	}
X}
X
Xstatic
XRUnsetrowNet(net)
XNnet *net;
X{
X	net->row = 0;
X}
X
Xstatic
XRSetrowNet(net)		/* set a net into a row */
XNnet *net;
X{
XNrow *row, *RFindRow();
X
X	if (net->row) return;	/* nop if already set */
X	row = RFindRow(NCurBase,net->rownum);
X	if (!row) {
X		printf("Can't find row %d for net %s\n",
X			net->rownum, net->name);
X		return;
X	}
X	net->row = row;
X	insertp(&(row->netlist),(char *)net);
X}
X
Xstatic
XRUnSplitNet(net)
XNnet *net;
X{
Xchar *splitp;
Xextern int RUnSplitConn();
X
X	splitp = index(net->name,SPLITCHAR);
X	if (!splitp) return;		/* not a split net */
X	/* OK, it's one of ours, undo it */
X	NDoGroup(&(net->connlist),RUnSplitConn);
X	if (net->connlist.count!=0)
X		fatalerr("net count!=0 for net %s", net->name);
X}
X
Xstatic
XRFreeSplitNet(net)
XNnet *net;
X{
X	if (!index(net->name,SPLITCHAR)) return;
X	NIFreeNet(net);
X}
X
Xstatic
XRSplitNet(net)
XNnet *net;
X{
XNconn *conn;
Xint cboxrow;
Xint connside, connrow;
Xint i;
Xint minrow,maxrow;
Xchar namebuf[516];
Xchar *namebufcpy;
XNnet *newnet;
Xchar *thisname, *lastname;
XNbox *newbox;
XNconn *newconn;
X
X	minrow=maxrow=0;
X	for (i=0; i<net->connlist.count; i++) {
X		conn = net->connlist.d.conn[i];
X		connside = conn->side;	/* NSEW */
X		cboxrow = conn->box->rownum;
X		connrow = cboxrow+((connside==N||connside==E)?1:-1);
X		if (i==0 || connrow<minrow) minrow=connrow;
X		if (i==0 || connrow>maxrow) maxrow=connrow;
X	}
X	if (minrow==maxrow) return;	/* all in one channel */
X	lastname = "";
X	for (i=minrow; i<=maxrow; i+=2) {
X		namebufcpy = 0;
X		sprintf(namebuf,"%s%c%s%d",net->name,SPLITCHAR,
X			((i<0)?"m":""),((i<0)?-i:i));
X		newnet = NFindNet(NCurBase,namebuf);
X		if (!newnet) {
X			newnet = NCreateNet(strsav(namebuf),i);
X		}
X		thisname = newnet->name;
X		if (i>minrow) {
X			newbox = NFindBox(NCurBase,thisname);
X			if (newbox) {
X				newbox->rownum = i-1;
X			} else {
X				newbox = NCreateBox(strsav(namebuf),0,0,0,0,
X					"",0,0,"",i-1,0);
X			}
X			newbox->parflags |= ROWSET;
X			NFreeGroup(&(newbox->connlist),NIFreeConn);
X			newconn = NCreateConn(strsav(newbox->name),
X				strsav(thisname),
X				0,0,strsav(NorEstr),strsav(thisname));
X			NLinkConnBox(newconn);
X			newconn = NCreateConn(strsav(newbox->name),
X				strsav(lastname),
X				0,0,strsav(SorWstr),strsav(lastname));
X			NLinkConnBox(newconn);
X		}
X		lastname = thisname;
X	}
X	for (i=0; i<net->connlist.count; i++) {
X		conn = net->connlist.d.conn[i];
X		connside = conn->side;	/* NSEW */
X		cboxrow = conn->box->rownum;
X		connrow = cboxrow+((connside==N||connside==E)?1:-1);
X		sprintf(namebuf,"%s%c%s%d",conn->netname,SPLITCHAR,
X			((connrow<0)?"m":""),((connrow<0)?-connrow:connrow));
X		namebufcpy = XALLOC(char,strlen(namebuf)+1);
X		strcpy(namebufcpy,namebuf);
X		tfree(conn->netname);
X		conn->netname = namebufcpy;
X	}
X}
X
Xstatic
XRClearOrderNet(net)
XNnet *net;
X{
X	net->parflags &= ~ORDERSET;
X}
X
Xstatic
XROrderCNet(net,side,negdir)
XNnet *net;
Xint side;
Xint negdir;
X{
XNgroup clist;
Xint i,j;
XNbox *box;
XNconn *cp;
X
X	NClearGroup(&clist);
X	for (i=0; i<net->connlist.count; i++) {
X		/* collect all conns on the side of interest */
X		cp = net->connlist.d.conn[i];
X		if (cp->side==side && cp->box) {
X			insertp(&clist,(char *)cp);
X		}
X	}
X	if (clist.count==0) return;
X	qsort((char *)clist.d.conn,clist.count,
X		sizeof(clist.d.conn[0]),RCmpConn);
X	for (i=0; i<clist.count; i++) {		/* see if any boxes set yet */
X		box = clist.d.conn[i]->box;
X		if (box->parflags & ORDERSET) break;
X	}
X	if (i>=clist.count) {		/* no boxes set yet */
X		if (negdir) i=clist.count;
X		else i=0;
X	}
X	for (j=i; j<clist.count; j++) {		/* count up from i */
X		ROrderBox(clist.d.conn[j]->box,0);
X	}
X	for (j=i-1; j>=0; j--) {		/* count down from i */
X		ROrderBox(clist.d.conn[j]->box,1);
X	}
X	if (clist.d.x) tfree((char *)clist.d.x);
X}
X
Xstatic
XROrderNet(net,negdir)	/* sets orders in neighboring boxes */
XNnet *net;
Xint negdir;		/* if set, expand in negative direction */
X{
X	if (net->parflags & ORDERSET) return;
X	net->parflags |= ORDERSET;
X	if (negdir)
X		net->rowpos = --(net->row->rowposmin);
X	else
X		net->rowpos = (net->row->rowposmax)++;
X	ROrderCNet(net,SorW,negdir); /* order the boxes to our south or west */
X	ROrderCNet(net,NorE,negdir); /* order the boxes to our north or east */
X}
X
Xstatic
XRSpanNet(net)	/* calculate the span for a net */
XNnet *net;
X{
Xint i;
XNconn *conn;
Xint max,min;
X
X	max = min = 0;
X	for (i=0; i<net->connlist.count; i++) {
X		conn = net->connlist.d.conn[i];
X		if (i==0 || conn->apos.vX > max) max=conn->apos.vX;
X		if (i==0 || conn->apos.vX < min) min=conn->apos.vX;
X	}
X	net->maxpos = max;
X	net->minpos = min;
X}
X
Xstatic int
XRCmpNet(n1,n2)
XNnet **n1, **n2;
X{
X	return (*n1)->minpos - (*n2)->minpos;
X}
X
Xstatic
XRNetForceNet(net,orgconn,pnforce,pncount)
XNnet *net;
XNconn *orgconn;	/* the source connector to calculate the force from */
Xint *pnforce;	/* return value - total net force */
Xint *pncount;	/* return value - count of net runs */
X{
Xint i;
XNconn *conn;
Xint orgx;
Xint nforce;
Xint ncount;
X
X	orgx = orgconn->apos.vX;
X	nforce = 0;
X	ncount = 0;
X	for (i=0; i<net->connlist.count; i++) {
X		conn = net->connlist.d.conn[i];
X		if (conn==orgconn) continue;
X		nforce += conn->apos.vX - orgx;
X		ncount++;
X	}
X	*pnforce = nforce;
X	*pncount = ncount;
X}
X
Xstatic
XRSetAngleNet(net)
XNnet *net;
X{
Xint i;
XNconn *conn;
Xint nconn, sconn, econn, wconn;
Xint nsum, ssum, esum, wsum;
X
X	if (net->connlist.count<=1) return;
X	nconn = sconn = econn = wconn = 0;
X	nsum = ssum = esum = wsum = 0;
X	net->track = 0;
X	for (i=0; i<net->connlist.count; i++) {
X		conn = net->connlist.d.conn[i];
X		switch (conn->side) {
X		case N:
X			nconn++;
X			nsum += conn->apos.X;
X			break;
X		case S:
X			sconn++;
X			ssum += conn->apos.X;
X			break;
X		case E:
X			econn++;
X			esum += conn->apos.Y;
X			break;
X		case W:
X			wconn++;
X			wsum += conn->apos.Y;
X			break;
X		default: break;
X		}
X	}
X	if      (nconn>sconn) net->angle = 'S';
X	else if (sconn>nconn) net->angle = 'N';
X	else if (econn>wconn) net->angle = 'W';
X	else if (wconn>econn) net->angle = 'E';
X	else if (esum>wsum) net->angle = 'L';	/* leans to the left */
X	else if (wsum>esum) net->angle = 'R';
X	else if (nsum>ssum) net->angle = 'L';
X	else if (ssum>nsum) net->angle = 'R';
X	else net->angle = 0;
X}
X
Xstatic
XRRouteNet(net)
XNnet *net;
X{
Xint i;
XNtrack *track;
XNconn *c1, *c2, *conn;
Xint cpos;
Xint NFreeGroupOnly();
X
X	NFreeGroup(&(net->pathlist),NFreeGroupOnly);
X	if (net->connlist.count<=1) return;
X	track = net->track;
X	NSetNet(net);		/* so we can use NCeatePath below */
X	cpos = track->pos;
X	if (net->connlist.count==2) {	/* common special case */
X		c1 = net->connlist.d.conn[0];
X		c2 = net->connlist.d.conn[1];
X		if (net->minpos==net->maxpos) {		/* no bends! */
X			NCreatePath(c1->apos.X,c1->apos.Y);
X			NCreatePath(c2->apos.X,c2->apos.Y);
X		}
X		else {
X			NCreatePath(c1->apos.X,c1->apos.Y);
X			if (HROW) {
X				NCreatePath(c1->apos.X,cpos);
X				NCreatePath(c2->apos.X,cpos);
X			} else {
X				NCreatePath(cpos,c1->apos.Y);
X				NCreatePath(cpos,c2->apos.Y);
X			}
X			NCreatePath(c2->apos.X,c2->apos.Y);
X		}
X	}
X	else {		/* more than two points */
X		if (HROW) {
X			NCreate1Path(net->minpos,cpos,net->maxpos,cpos);
X			for (i=0; i<net->connlist.count; i++) {
X				conn = net->connlist.d.conn[i];
X				NCreate1Path(conn->apos.X,conn->apos.Y,
X					conn->apos.X,cpos);
X			}
X		} else {
X			NCreate1Path(cpos,net->minpos,cpos,net->maxpos);
X			for (i=0; i<net->connlist.count; i++) {
X				conn = net->connlist.d.conn[i];
X				NCreate1Path(conn->apos.X,conn->apos.Y,
X					cpos,conn->apos.Y);
X			}
X		}
X	}
X}
X
Xstatic
XRUnSplitConn(conn)
XNconn *conn;
X{
Xchar *nnend;
X
X	if (!conn->box)
X		NLinkConnBox(conn);
X	nnend = index(conn->netname,SPLITCHAR);
X	if (!nnend) return;
X	if (conn->net)
X		removep(&(conn->net->connlist),(char *)conn);
X			/* remove from old (split) net */
X	*nnend = 0;	/* strip tail off name */
X	if (!conn->box) return;
X	if (!index(conn->box->name,SPLITCHAR)) {
X		NLinkConnNet(conn);	/* relink the net pointer */
X	}
X}
X
Xstatic
XRSelBConn(conn,rownum)
XNconn *conn;
Xint rownum;
X{
X	if (!conn->net) return;
X	switch (conn->side) {
X	case E: case N:
X		RSelNet(conn->net,rownum+1);
X		break;
X	case W: case S:
X		RSelNet(conn->net,rownum-1);
X		break;
X	}
X}
X
Xstatic
XRSelNConn(conn,rownum)
XNconn *conn;
Xint rownum;
X{
X	if (!conn->box) return;
X	switch (conn->side) {
X	case E: case N:
X		RSelBox(conn->box,rownum-1);
X		break;
X	case W: case S:
X		RSelBox(conn->box,rownum+1);
X		break;
X	}
X}
X
Xstatic int
XRCmpConn(c1,c2)
XNconn **c1, **c2;
X{
X	return (*c1)->pos.vX - (*c2)->pos.vX;
X}
X
Xstatic
XNrow *
XRFindRow(base,num)
XNbase *base;
Xint num;
X{
Xint i;
X
X	for (i=0; i<base->rowlist.count; i++) {
X		if (base->rowlist.d.row[i]->rownum==num)
X			return base->rowlist.d.row[i];
X	}
X	return 0;
X}
X
Xstatic
XRSetflagRow(row)
XNrow *row;
X{
X	if (row->boxlist.count)
X		row->parflags |= BOXROW;
X	else
X		row->parflags &= ~BOXROW;
X}
X
Xstatic int
XRSizeRow(row)
XNrow *row;
X{
Xint i;
Xint smax,s;
X
X	if (!(row->parflags & BOXROW)) return 0;	/* not a box row */
X	smax=0;
X	for (i=0; i<row->boxlist.count; i++) {
X		s = row->boxlist.d.box[i]->size.vY;
X		if (s>smax) smax=s;
X	}
X	row->size = smax;
X	return smax;
X}
X
Xstatic
XRClearOrderRow(row)
XNrow *row;
X{
X	row->rowposmin = row->rowposmax = 0;
X}
X
Xstatic
XRSortRow(row)	/* sorts the boxes in a row */
XNrow *row;
X{
X	if (!(row->parflags & BOXROW)) return;
X	qsort((char *)row->boxlist.d.box,row->boxlist.count,
X		sizeof(row->boxlist.d.box[0]),RCmpBox);
X			/* sort according to rowpos */
X	RNormalizeRow(row);
X}
X
Xstatic
XRNormalizeRow(row)
XNrow *row;
X{
XNbox *box;
Xint i,t;
X
X	t = 0;
X	for (i=0; i<row->boxlist.count; i++) {
X		box = row->boxlist.d.box[i];
X		box->origin.vX = t;
X		t += NCurBase->rowposspace + box->size.vX;
X	}
X	row->length = t-NCurBase->rowposspace;
X}
X
Xstatic
XRPositionRow(row,side)
XNrow *row;
Xint side;	/* position based on connectors on this side */
X{
X	if (!(row->parflags & BOXROW)) return;
X	RBalanceRow(row,side);
X	RSpreadRow(row,side);
X}
X
Xstatic
XRBalanceRow(row,side)	/* moves the row as a unit to a balanced position */
XNrow *row;
Xint side;	/* position based on connectors on this side */
X{
Xint i;
XNbox *box;
Xint nforce, ncount;
Xint sumnforce, sumncount;
Xint dist;
X
X	sumnforce = 0;
X	sumncount = 0;
X	for (i=0; i<row->boxlist.count; i++) {
X		box = row->boxlist.d.box[i];
X		RNetForceBox(box,side,&nforce,&ncount);
X		sumnforce += nforce;
X		sumncount += ncount;
X	}
X	if (sumncount==0) return;
X	dist = sumnforce/sumncount;
X	if (dist<0) return;
X	if (dist + row->length > NCurBase->maxrowlength)
X		dist = NCurBase->maxrowlength - row->length;
X	for (i=0; i<row->boxlist.count; i++) {
X		box = row->boxlist.d.box[i];
X		box->origin.vX += dist;
X		NDoGroup(&(box->connlist),NPosConn);
X		box->parflags &= ~POSITIONSET;
X	}
X}
X
Xstatic
XRSpreadRow(row,side)
XNrow *row;
Xint side;	/* position based on connectors on this side */
X{
Xint i;
XNbox *box;
Xint floor, ceil;
Xint nforce, ncount;
Xint dist;
Xint j;
XNbox *boxj;
Xint tfloor;
X
X	floor = 0;
X	for (i=0; i<row->boxlist.count; i++) {
X		box = row->boxlist.d.box[i];
X		RNetForceBox(box,side,&nforce,&ncount);
X		if (ncount==0) {
X			floor += box->size.vX + NCurBase->rowposspace;
X				/* raise floor, but place this box later */
X			continue;
X		}
X		dist = nforce/ncount;
X		if (dist>=0) break;
X		if (box->origin.vX + dist < floor)
X			box->origin.vX = floor;
X		else
X			box->origin.vX += dist;
X		NDoGroup(&(box->connlist),NPosConn);
X		floor = box->origin.vX + box->size.vX + NCurBase->rowposspace;
X		box->parflags |= POSITIONSET;
X		tfloor = box->origin.vX;
X		for (j=i-1; j>=0; j--) {
X			boxj = row->boxlist.d.box[j];
X			if (boxj->parflags & POSITIONSET) break;
X			tfloor -= boxj->size.vX + NCurBase->rowposspace;
X			boxj->origin.vX = tfloor;
X			boxj->parflags |= POSITIONSET;
X		}
X	}
X	ceil = NCurBase->maxrowlength;
X	for (i=row->boxlist.count-1; i>=0; i--) {
X		box = row->boxlist.d.box[i];
X		RNetForceBox(box,side,&nforce,&ncount);
X		if (ncount==0) {
X			ceil -= box->size.vX + NCurBase->rowposspace;
X			continue;
X		}
X		dist = nforce/ncount;
X		if (dist<=0) break;
X		if (box->origin.vX + box->size.vX + dist > ceil)
X			box->origin.vX = ceil - box->size.vX;
X		else
X			box->origin.vX += dist;
X		NDoGroup(&(box->connlist),NPosConn);
X		ceil = box->origin.vX - NCurBase->rowposspace;
X		box->parflags |= POSITIONSET;
X		tfloor = box->origin.vX + box->size.vX + NCurBase->rowposspace;
X		for (j=i+1; j<row->boxlist.count; j++) {
X			boxj = row->boxlist.d.box[j];
X			if (boxj->parflags & POSITIONSET) break;
X			boxj->origin.vX = tfloor;
X			tfloor += boxj->size.vX + NCurBase->rowposspace;
X			boxj->parflags |= POSITIONSET;
X		}
X	}
X}
X
X/* track routines */
X
Xstatic Ntrack *
XRNewTrack(n)
Xint n;
X{
XNtrack *track;
X
X	track = XCALLOC(Ntrack,1);
X	track->n = n;
X	track->netlist.count = track->netlist.alloc = 0;
X	track->netlist.d.net = 0;
X	return track;
X}
X
Xstatic
XRUseTrack(track,net)
XNtrack *track;
XNnet *net;
X{
X	track->parflags |= SPANSET;
X	insertp(&(track->netlist),(char *)net);
X}
X
Xstatic int	/* returns angle of the net which is in the way, 0 if open */
XRUnAvailTrack(track,min,max)
XNtrack *track;
Xint min,max;
X{
XNnet *net;
Xint i;
X
X	if (!(track->parflags & SPANSET)) return 0;
X	for (i=0; i<track->netlist.count; i++) {
X		net = track->netlist.d.net[i];
X		if (min>=net->maxpos+NCurBase->trackspace) continue;
X		if (max<=net->minpos-NCurBase->trackspace) continue;
X		return net->angle;	/* this net is in the way */
X	}
X	return 0;
X}
X
Xstatic Ntrack *
XRFindTrack(row,min,max,netangle)
XNrow *row;
Xint min,max;
Xint netangle;
X{
Xint i;
XNtrack *track, *lastavail;
Xint trackangle;
X
X/* find the last row in which the route DOES NOT fit, then return the
X * next row after that! */
X	lastavail = 0;
X	for (i=row->tracklist.count-1; i>=0; i--) {
X		track = row->tracklist.d.track[i];
X		trackangle = RUnAvailTrack(track,min,max);
X		if (!trackangle)
X			lastavail = track;
X		else
X			if (trackangle==netangle) break;
X		/* if angles are different, continue looking */
X	}
X	if (lastavail) return lastavail;
X	return 0;
X
X#if 0	/* greedy algorithm - doesn't do quite what we want */
X	for (i=0; i<row->tracklist.count; i++) {
X		track = row->tracklist.d.track[i];
X		if (!(RUnAvailTrack(track,min,max))) return track;
X	}
X	return 0;
X#endif
X}
X
Xstatic
XRClearTrack(track)
XNtrack *track;
X{
X	NFreeGroupOnly(&(track->netlist));
X	track->parflags = 0;
X}
X
Xstatic
XRFreeTrack(track)
XNtrack *track;
X{
X	NFreeGroupOnly(&(track->netlist));
X	tfree((char *)track);
X}
X
Xstatic
XRChanSizeRow(row)	/* calculate required number of tracks */
XNrow *row;
X{
Xint i;
XNnet *net;
XNtrack *track;
X
X	if (row->parflags & BOXROW) return;
X	NFreeGroup(&(row->tracklist),RFreeTrack);
X	NDoGroup(&(row->netlist),RSpanNet);	/* find span of each net */
X	qsort((char *)row->netlist.d.net,row->netlist.count,
X		sizeof(row->netlist.d.net[0]),RCmpNet);
X	NDoGroup(&(row->netlist),RSetAngleNet);
X	for (i=row->netlist.count-1; i>=0; i--) {
X		net = row->netlist.d.net[i];
X		if (net->connlist.count<=1) continue;
X		switch (net->angle) {
X		case 'W': case 'R': case 'S':
X			break;
X		default:
X			continue;
X		}
X		track = RFindTrack(row,net->minpos,net->maxpos,net->angle);
X			 /* see where it can fit */
X		if (!track) {		/* have to make a new track */
X			track = RNewTrack(row->tracklist.count);
X			insertp(&(row->tracklist),(char *)track);
X		}
X		net->track = track;
X		RUseTrack(track,net);
X	}
X	for (i=0; i<row->netlist.count; i++) {
X		net = row->netlist.d.net[i];
X		if (net->track || net->connlist.count<=1) continue;
X		track = RFindTrack(row,net->minpos,net->maxpos,net->angle);
X			 /* see where it can fit */
X		if (!track) {		/* have to make a new track */
X			track = RNewTrack(row->tracklist.count);
X			insertp(&(row->tracklist),(char *)track);
X		}
X		net->track = track;
X		RUseTrack(track,net);
X	}
X	row->size = NCurBase->trackspace * (row->tracklist.count+1);
X}
X
Xstatic
XRRouteRow(row)
XNrow *row;
X{
Xint i;
XNtrack *track;
X
X	if (row->parflags & BOXROW) return;
X	for (i=0; i<row->tracklist.count; i++) {
X		track = row->tracklist.d.track[i];
X		track->pos = row->pos + NCurBase->trackspace*(1+i);
X	}
X	NDoGroup(&(row->tracklist),RClearTrack);	/* clear min/max */
X	NDoGroup(&(row->netlist),RRouteNet);	/* route all nets */
X}
X
Xint
XRSelect(boxname)	/* select rows for all boxes and nets */
Xchar *boxname;
X{
XNbox *box;
X
X	if (!NCurBase) {
X		printf("no data to place\n");
X		return 0;
X	}
X	NDoGroup(&(NCurBase->boxlist),RUnmarkBox);
X	NDoGroup(&(NCurBase->netlist),RUnmarkNet);
X
X	if (boxname) {	/* see if preferred root for placement */
X		box = NFindBox(NCurBase,boxname);
X		if (box) RSelectBox(box);
X	}
X	NDoGroup(&(NCurBase->boxlist),RSelectBox);	/* put in new row */
X
X	return 1;
X}
X
X/* UnFeed removes any previously inserted feedthroughs */
Xint
XRUnFeed()
X{
X	if (!NCurBase) {
X		printf("no data to place\n");
X		return 0;
X	}
X	NDoGroup(&(NCurBase->boxlist),RUnSplitBox);
X	NRDoGroup(&(NCurBase->boxlist),RFreeSplitBox);
X	NDoGroup(&(NCurBase->netlist),RUnSplitNet);
X	NRDoGroup(&(NCurBase->netlist),RFreeSplitNet);
X	return 1;
X}
X
Xint
XRFeed()		/* make feedthroughs */
X{
X
X	if (!NCurBase) {
X		printf("no data to place\n");
X		return 0;
X	}
X	NDoGroup(&(NCurBase->netlist),RSplitNet);
X		/* divide nets up when spanning rows */
X	NDoGroup(&(NCurBase->netlist),NClearNetConns);
X	NDoGroup(&(NCurBase->connlist),NLinkConnNet);
X	return 1;
X}
X
Xint
XRReFeed()	/* remove old feedthroughs and insert new */
X{
X	if (!RUnFeed()) return 0;
X	if (!RFeed()) return 0;
X	return 1;
X}
X
Xint
XRSpace()	/* set the spacing for the rows, set one coord in boxes */
X{
Xextern int NFreeRow();
Xint rowmax=0;
Xint rowmin=0;
Xint r,rowcount;
Xint i;
Xint pos;
XNrow *row;
X
X	if (!NCurBase) {
X		printf("no data to place\n");
X		return 0;
X	}
X	NSetBase(NCurBase);		/* so we can use NCreateRow */
X	NFreeGroup(&(NCurBase->rowlist),NFreeRow);	/* dump all old rows */
X	NDoGroup(&(NCurBase->boxlist),RUnsetrowBox);
X	NDoGroup(&(NCurBase->netlist),RUnsetrowNet);
X	for (i=0; i<NCurBase->boxlist.count; i++) {
X		r = NCurBase->boxlist.d.box[i]->rownum;
X		if (i==0 || r>rowmax) rowmax=r;
X		if (i==0 || r<rowmin) rowmin=r;
X	}
X	for (i=0; i<NCurBase->netlist.count; i++) {
X		r = NCurBase->netlist.d.net[i]->rownum;
X		if (r>rowmax) rowmax=r;
X		if (r<rowmin) rowmin=r;
X	}
X	rowcount = rowmax-rowmin+1;
X	for (i=0; i<rowcount; i++) {
X		NCreateRow(i+rowmin,0,0);	/* put in new rows */
X	}
X	NDoGroup(&(NCurBase->boxlist),RSetrowBox);
X	NDoGroup(&(NCurBase->netlist),RSetrowNet);
X		/* put all the boxes and nets into their rows */
X	pos = 0;
X	for (i=0; i<NCurBase->rowlist.count; i++) {
X		row = NCurBase->rowlist.d.row[i];
X		row->pos = pos;
X		if (row->boxlist.count)
X			row->parflags |= BOXROW;
X		pos += NCurBase->interrowspace + RSizeRow(row);
X	}
X	NDoGroup(&(NCurBase->boxlist),RSetrposBox);
X	NDoGroup(&(NCurBase->connlist),NPosConn);
X	return 1;
X}
X
Xstatic
XRSetPtrs()	/* make sure pointers are set up (for incremental p/r) */
X{
X	/* make sure box and net pointers to row are in */
X	NDoGroup(&(NCurBase->boxlist),RSetrowBox);
X	NDoGroup(&(NCurBase->netlist),RSetrowNet);
X	NDoGroup(&(NCurBase->rowlist),RSetflagRow);
X}
X
Xint
XROrder(boxname)	/* order the boxes in each row */
Xchar *boxname;
X{
Xint i;
XNbox *box;
X
X	if (!NCurBase) {
X		printf("no data to place\n");
X		return 0;
X	}
X
X	RSetPtrs();
X
X	/* now start the ordering within each row */
X	NDoGroup(&(NCurBase->boxlist),RClearOrderBox);
X	NDoGroup(&(NCurBase->netlist),RClearOrderNet);
X	NDoGroup(&(NCurBase->rowlist),RClearOrderRow);
X		/* clear out any previous ordering info */
X
X	if (boxname) {	/* see if preferred root for placement */
X		box = NFindBox(NCurBase,boxname);
X		if (box) ROrderBox(box,0);
X	}
X	for (i=0; i<NCurBase->boxlist.count; i++) {
X		ROrderBox(NCurBase->boxlist.d.box[i],0);
X	}
X	NDoGroup(&(NCurBase->rowlist),RSortRow);
X	NDoGroup(&(NCurBase->connlist),NPosConn);
X	return 1;
X}
X
Xint
XRPosition()	/* position the boxes within each row */
X{
Xint i;
XNrow *row;
Xint maxlength;
Xint rowi;
X
X	if (!NCurBase) {
X		printf("no data to place\n");
X		return 0;
X	}
X
X	RSetPtrs();
X
X	NDoGroup(&(NCurBase->rowlist),RNormalizeRow);
X	maxlength = -1;
X	for (i=0; i<NCurBase->rowlist.count; i++) {
X		row = NCurBase->rowlist.d.row[i];
X		if (!(row->parflags & BOXROW)) continue;
X		if (row->length > maxlength) {
X			maxlength = row->length;
X			rowi = i;
X		}
X	}
X	NCurBase->maxrowlength = maxlength;
X	for (i=rowi-1; i>=0; i--) {
X		RPositionRow(NCurBase->rowlist.d.row[i],NorE);
X	}
X	for (i=rowi+1; i<NCurBase->rowlist.count; i++) {
X		RPositionRow(NCurBase->rowlist.d.row[i],SorW);
X	}
X	return 1;
X}
X
Xint
XRRoute()	/* do the channel route */
X{
Xint i;
Xint t;
XNrow *row;
X
X	if (!NCurBase) {
X		printf("no data to place\n");
X		return 0;
X	}
X
X	RSetPtrs();
X
X	NDoGroup(&(NCurBase->connlist),NPosConn);
X	NDoGroup(&(NCurBase->rowlist),RChanSizeRow);
X		/* calculate the channel size for each row */
X	t = 0;
X	for (i=0; i<NCurBase->rowlist.count; i++) {
X		row = NCurBase->rowlist.d.row[i];
X		row->pos = t;
X		t += row->size;
X	}
X	NDoGroup(&(NCurBase->boxlist),RSetrposBox);
X	NDoGroup(&(NCurBase->connlist),NPosConn);
X	NDoGroup(&(NCurBase->rowlist),RRouteRow);
X		/* do the actual channel routing */
X	return 1;
X}
X
XRSpacepar(boxname)	/* RSpace and the rest */
Xchar *boxname;
X{
X	if (!RSpace()) return 0;
X	if (!ROrder(boxname)) return 0;
X	if (!RPosition()) return 0;
X	if (!RRoute()) return 0;
X	return 1;
X}
X
XRReFeedpar(boxname)	/* RFeed and the rest */
Xchar *boxname;
X{
X	if (!RReFeed()) return 0;
X	if (!RSpacepar(boxname)) return 0;
X	return 1;
X}
X
XRpar(boxname)		/* do it all */
Xchar *boxname;
X{
X	if (!RSelect(boxname)) return 0;
X	if (!RReFeedpar(boxname)) return 0;
X	return 1;
X}
X
X/* end */
END_OF_FILE
if test 26098 -ne `wc -c <'par.c'`; then
    echo shar: \"'par.c'\" unpacked with wrong size!
fi
# end of 'par.c'
fi
echo shar: End of archive 3 \(of 3\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 3 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.