--routePaths2.mesa
DIRECTORY RouteDefs;
RoutePaths2:PROGRAM IMPORTS RouteDefs EXPORTS RouteDefs=BEGIN
OPEN RouteDefs;
Error:SIGNAL=CODE;
hot:PlaceListPtr←NIL;
places:PlaceListPtr←NIL;--all the corners
saves:PlaceListPtr←NIL;--middles for this circuit
thisCircuit:Circuit←0;
ChannelLevelRouting:PUBLIC CtlProc=BEGIN
ShowLabel["PATH"];
ScavengePaths;
IF places#NIL THEN {Error; places←NIL};
EnumerateRectangles[AddFourPlaces];
EnumerateRectangles[AddLimitPointers];
ShowPlaces[];
DoCircuits;
ScavengePlaces;
CheckPaths;
RETURN[-1];
END;
ScavengePaths:PROCEDURE=BEGIN
UNTIL paths=NIL DO
p:PathwayListPtr←paths;
paths←p.t;
UNTIL p.h.path=NIL DO
q:PathListPtr←p.h.path;
p.h.path←q.t; FreePath[q.h]; FreeList[q];
ENDLOOP;
FreePathway[p.h];
FreeList[p];
ENDLOOP;
END;
AddLimitPointers:PROCEDURE[rect:RectanglePtr]=BEGIN
SELECT rect.orient FROM hor,vert=>NULL; ENDCASE=>RETURN;
BEGIN
x1:Lambda=rect.pos.x;
x2:Lambda=rect.pos.x+rect.sizeL.x;
y1:Lambda=rect.pos.y;
y2:Lambda=rect.pos.y+rect.sizeL.y;
FOR pl:PlaceListPtr←places, pl.t UNTIL pl=NIL DO
p:PlacePtr=pl.h;
IF rect.orient =hor
THEN IF p.pos.y=y1 OR p.pos.y=y2 THEN
{IF p.pos.x#x1 THEN p.uw←rect; IF p.pos.x#x2 THEN p.ue←rect}
ELSE IF p.pos.x=x1 OR p.pos.x=x2 THEN
{IF p.pos.y#y1 THEN p.us←rect; IF p.pos.y#y2 THEN p.un←rect};
ENDLOOP;
END; END;
AddFourPlaces:PROCEDURE[rect:RectanglePtr]=BEGIN
WestSide:PROCEDURE[y:Lambda,yes:BOOLEAN←FALSE]=BEGIN
IF ~(yes OR y IN (pos.y..pos.y+size.y)) THEN RETURN;
new←AddPlace[pos.x,y];
IF this#NIL AND new#NIL THEN {this.n←new; new.s←this};
IF new#NIL THEN new.perm←TRUE;
this←new;
END;
NorthSide:PROCEDURE[x:Lambda,yes:BOOLEAN←FALSE]=BEGIN
IF ~(yes OR x IN (pos.x..pos.x+size.x)) THEN RETURN;
new←AddPlace[x,pos.y+size.y];
IF this#NIL AND new#NIL THEN {this.e←new; new.w←this};
IF new#NIL THEN new.perm←TRUE;
this←new;
END;
EastSide:PROCEDURE[y:Lambda,yes:BOOLEAN←FALSE]=BEGIN
IF ~(yes OR y IN (pos.y..pos.y+size.y)) THEN RETURN;
new←AddPlace[pos.x+size.x,y];
IF this#NIL AND new#NIL THEN {this.s←new; new.n←this};
IF new#NIL THEN new.perm←TRUE;
this←new;
END;
SouthSide:PROCEDURE[x:Lambda,yes:BOOLEAN←FALSE]=BEGIN
IF ~(yes OR x IN (pos.x..pos.x+size.x)) THEN RETURN;
new←AddPlace[x,pos.y];
IF this#NIL AND new#NIL THEN {this.w←new; new.e←this};
IF new#NIL THEN new.perm←TRUE;
this←new;
END;
pos:CoordL=rect.pos;
size:CoordL=rect.sizeL;
this,save,new:PlacePtr←NIL;
f:RectanglePtr←NIL;
WestSide[pos.y,TRUE];
save←this;
IF (f←rect.w)#NIL THEN {WestSide[f.pos.y]; WestSide[f.pos.y+f.sizeL.y]};
WestSide[pos.y+size.y,TRUE];
IF (f←rect.n)#NIL THEN {NorthSide[f.pos.x]; NorthSide[f.pos.x+f.sizeL.x]};
NorthSide[pos.x+size.x,TRUE];
IF (f←rect.e)#NIL THEN {EastSide[f.pos.y+f.sizeL.y]; EastSide[f.pos.y]};
EastSide[pos.y,TRUE];
IF (f←rect.s)#NIL THEN {SouthSide[f.pos.x+f.sizeL.x]; SouthSide[f.pos.x]};
IF this#NIL AND save#NIL THEN {this.w←save; save.e←this};
END;
AddPlace:PROCEDURE[x,y:Lambda] RETURNS[p:PlacePtr]=BEGIN
pl:PlaceListPtr;
IF x NOT IN (0..problem.chipSize.x) THEN RETURN[NIL];
IF y NOT IN (0..problem.chipSize.y) THEN RETURN[NIL];
FOR pl←places, pl.t UNTIL pl=NIL
DO p←pl.h; IF p.pos.x=x AND p.pos.y=y THEN RETURN; ENDLOOP;
FOR pl←saves, pl.t UNTIL pl=NIL
DO p←pl.h; IF p.pos.x=x AND p.pos.y=y THEN RETURN; ENDLOOP;
p←AllocatePlace[];
pl←AllocateList[];
p.pos←[x,y];
pl↑←[p,places];
places←pl;
END;
ShowPlaces:PROCEDURE=BEGIN
ShowLabel["PLACES"];
FOR pl:PlaceListPtr←places, pl.t UNTIL pl=NIL DO ShowAPlace[pl.h]; ENDLOOP;
FOR pl:PlaceListPtr←saves, pl.t UNTIL pl=NIL DO ShowAPlace[pl.h]; ENDLOOP;
END;
ShowAPlace:PROCEDURE[p:PlacePtr]=BEGIN
Return[];
ShowPoint[p.pos];
ShowString[" n= "];
IF p.n = NIL THEN ShowString["none"] ELSE ShowPoint[p.n.pos];
ShowString[" s= "];
IF p.s = NIL THEN ShowString["none"] ELSE ShowPoint[p.s.pos];
ShowString[" e= "];
IF p.e = NIL THEN ShowString["none"] ELSE ShowPoint[p.e.pos];
ShowString[" w= "];
IF p.w = NIL THEN ShowString["none"] ELSE ShowPoint[p.w.pos];
END;
DoCircuits:PROCEDURE=BEGIN
FOR circuit:Circuit←1,circuit+1 DO
IF allPaths#NIL THEN {Error; allPaths←NIL};
thisCircuit←circuit;
InitializePlaces[];
hot←saves←NIL;
circuitCount←0;
EnumerateRectangles[InitializeHot];
IF circuitCount=0 THEN EXIT;
IF circuitCount<2 THEN Error ELSE BEGIN
pathway:PathwayPtr←AllocatePathway[];
pwl:PathwayListPtr←AllocateList[];
pathway↑←[circuit,NIL];
pwl↑←[pathway,paths];
paths←pwl;
Return[];
UNTIL circuitCount<2 OR hot=NIL DO GoPlace[]; ENDLOOP;
SetAboveAndBelowAndUsed[];
SetHiAndLo[];
MakePathFromLinks[];
--ShowPath[];
IF allPaths#NIL THEN ReducePath[];
ShowPath[];
pathway.path←allPaths;
allPaths←NIL;
ScavengeHot[]; --leaves hot nil
ScavengeSaves[]; --leaves saves nil
ScavengeLinks[]; --leaves links nil
END; ENDLOOP;
END;
ScavengeHot:PROCEDURE=BEGIN
UNTIL hot=NIL DO
pl:PlaceListPtr←hot;
hot←pl.t;
FreeList[pl];
ENDLOOP;
END;
ScavengeSaves:PROCEDURE=BEGIN
UNTIL saves=NIL DO
pl:PlaceListPtr←saves;
p:PlacePtr←pl.h;
saves←pl.t;
IF p.e#NIL THEN p.e.w←p.w;
IF p.w#NIL THEN p.w.e←p.e;
IF p.n#NIL THEN p.n.s←p.s;
IF p.s#NIL THEN p.s.n←p.n;
FreePlace[p];
FreeList[pl];
ENDLOOP;
END;
ShowPoint:PROCEDURE[a:CoordL]={WritePoint[a.x,a.y]};
ScavengePlaces:PROCEDURE=BEGIN
UNTIL places=NIL DO
pl:PlaceListPtr←places;
places←pl.t;
FreePlace[pl.h];
FreeList[pl];
ENDLOOP;
END;
InitializePlaces:PROCEDURE=BEGIN
FOR pl:PlaceListPtr←places, pl.t UNTIL pl=NIL DO
p:PlacePtr=pl.h;
p.score←bigLambda; p.back←NIL; p.circuit←0; p.done←FALSE;
ENDLOOP;
END;
InitializeHot:PROCEDURE[rect:RectanglePtr]=BEGIN
--for each source this circuit, if not on grid add to grid (removably)
-- and set score to zero
circuit:Circuit=thisCircuit;
x1:Lambda=rect.pos.x;
x2:Lambda=x1+rect.sizeL.x;
y1:Lambda=rect.pos.y;
y2:Lambda=y1+rect.sizeL.y;
hor:BOOLEAN=rect.orient=hor;
FOR el:EventListPtr←rect.events, el.t UNTIL el=NIL DO
e:EventPtr=el.h;
IF e.circuit#circuit THEN LOOP;
circuitCount←circuitCount+1;
BEGIN
onNS:BOOLEAN=(e.side=n OR e.side=s);
top:Lambda=IF onNS THEN rect.sizeL.x ELSE rect.sizeL.y;
off:Lambda=MIN[top-1,MAX[1,e.offset]];
thisPos:CoordL=IF onNS THEN [x1+off,y1] ELSE [x1,y1+off];
otherPos:CoordL=IF onNS THEN [x1+off,y2] ELSE [x2,y1+off];
useOther:BOOLEAN=SELECT e.where FROM top,right=>hor,
ENDCASE=>NOT hor;
myPos:CoordL=IF useOther THEN otherPos ELSE thisPos;
myPlace:PlacePtr=FindPlace[myPos];
IF myPlace#NIL
THEN {myPlace.score←0; myPlace.circuit←e.net.netNo; LOOP};
BEGIN
saveList:PlaceListPtr=AllocateList[];
hotList:PlaceListPtr=AllocateList[];
save2List:PlaceListPtr=AllocateList[];
this:PlacePtr=AllocatePlace[];
other:PlacePtr=AllocatePlace[];
mine:PlacePtr=IF useOther THEN other ELSE this;
this.pos←thisPos;
other.pos←otherPos;
this.score←other.score←bigLambda;
mine.score←0; mine.circuit←e.net.netNo;
IF onNS THEN BEGIN
this.n←other; other.s←this;
this.w←AddPlace2[x1,y1,this]; IF this.w#NIL THEN this.w.e←this;
this.e←AddPlace2[x2,y1,this]; IF this.e#NIL THEN this.e.w←this;
other.w←AddPlace2[x1,y2,other]; IF other.w#NIL THEN other.w.e←other;
other.e←AddPlace2[x2,y2,other]; IF other.e#NIL THEN other.e.w←other;
this.ue←IF this.e=NIL THEN NIL ELSE this.e.uw;
this.uw←IF this.w=NIL THEN NIL ELSE this.w.ue;
other.ue←IF other.e=NIL THEN NIL ELSE other.e.uw;
other.uw←IF other.w=NIL THEN NIL ELSE other.w.ue;
END
ELSE BEGIN
this.w←other; other.e←this;
this.s←AddPlace2[x1,y1,this]; IF this.s#NIL THEN this.s.n←this;
this.n←AddPlace2[x1,y2,this]; IF this.n#NIL THEN this.n.s←this;
other.s←AddPlace2[x2,y1,other]; IF other.s#NIL THEN other.s.n←other;
other.n←AddPlace2[x2,y2,other]; IF other.n#NIL THEN other.n.s←other;
this.un←IF this.n=NIL THEN NIL ELSE this.n.us;
this.us←IF this.s=NIL THEN NIL ELSE this.s.un;
other.un←IF other.n=NIL THEN NIL ELSE other.n.us;
other.us←IF other.s=NIL THEN NIL ELSE other.s.un;
END;
hotList↑←[mine,hot];
hot←hotList;
saveList↑←[this,saves];
save2List↑←[other,saveList];
saves←save2List;
END; END; ENDLOOP;
END;
FindPlace:PROCEDURE[w:CoordL] RETURNS[p:PlacePtr]=BEGIN
FOR pl:PlaceListPtr←places, pl.t UNTIL pl=NIL
DO p←pl.h; IF p.pos=w THEN RETURN[p]; ENDLOOP;
FOR pl:PlaceListPtr←saves, pl.t UNTIL pl=NIL
DO p←pl.h; IF p.pos=w THEN RETURN[p]; ENDLOOP;
RETURN[NIL];
END;
AddPlace2:PROCEDURE[x,y:Lambda,new:PlacePtr] RETURNS[pp:PlacePtr]=BEGIN
pp←AddPlace[x,y];
FOR hl:PlaceListPtr←saves,hl.t UNTIL hl=NIL DO
hhh:PlacePtr←hl.h;
IF new.pos.x=x AND hhh.pos.x=x AND Between[hhh.pos.y,new.pos.y,y]
OR new.pos.y=y AND hhh.pos.y=y AND Between[hhh.pos.x,new.pos.x,x]
THEN {pp←hhh; x←pp.pos.x; y←pp.pos.y};
ENDLOOP;
FOR hl:PlaceListPtr←places,hl.t UNTIL hl=NIL DO
hhh:PlacePtr←hl.h;
IF new.pos.x=x AND hhh.pos.x=x AND Between[hhh.pos.y,new.pos.y,y]
OR new.pos.y=y AND hhh.pos.y=y AND Between[hhh.pos.x,new.pos.x,x]
THEN {pp←hhh; x←pp.pos.x; y←pp.pos.y};
ENDLOOP;
END;
Between:PROCEDURE[a,b,c:Lambda] RETURNS[BOOLEAN]=BEGIN
RETURN[IF b<c THEN a IN (b..c) ELSE a IN (c..b)];
END;
circuitCount:INTEGER;
GoPlace:PROCEDURE=BEGIN
bestScore:Lambda←bigLambda;
best,back:PlacePtr←NIL;
next,prev:PlaceListPtr←NIL;
FOR hl:PlaceListPtr←hot,next UNTIL hl=NIL DO
h:PlacePtr←hl.h;
live:BOOLEAN←FALSE;
Try:PROCEDURE[t:PlacePtr,s:Lambda]=BEGIN
thisScore:Lambda←h.score+ABS[s];
IF t.circuit=h.circuit THEN RETURN;
IF thisScore<bestScore
THEN {bestScore←thisScore; best←t; back←h};
live←TRUE;
END;
Goable:PROCEDURE[w:PlacePtr,z:BOOLEAN,s:RectanglePtr]=BEGIN
IF w=NIL THEN RETURN ELSE BEGIN
l:Lambda=IF z THEN w.pos.y-h.pos.y ELSE w.pos.x-h.pos.x;
IF s=NIL OR s.used<s.avail THEN Try[w,l];
END; END;
Goable[h.n,TRUE ,h.un];
Goable[h.s,TRUE ,h.us];
Goable[h.e,FALSE,h.ue];
Goable[h.w,FALSE,h.uw];
next←hl.t;
IF ~live THEN {IF prev=NIL THEN hot←next ELSE prev.t←next; FreeList[hl]}
ELSE prev←hl;
ENDLOOP;
IF best=NIL THEN {Log[]; RETURN};
IF best.score=bigLambda THEN BEGIN
temp:PlaceListPtr←AllocateList[];
temp↑←[best,hot];
hot←temp;
best.score←bestScore;
best.back←back;
best.circuit←back.circuit;
END
ELSE BEGIN
FOR pl:PlacePtr←best, pl.back UNTIL pl.back=NIL OR pl.done DO
AddPath[pl,pl.back]; pl.done←TRUE; --wierd
ENDLOOP;
FOR pl:PlacePtr←back, pl.back UNTIL pl.back=NIL OR pl.done DO
AddPath[pl,pl.back]; pl.done←TRUE;
ENDLOOP;
AddPath[best,back];
from←back.circuit;
to←best.circuit;
ChangeCircuit[back];
FOR zz:PlaceListPtr←saves,zz.t UNTIL zz=NIL DO
IF zz.h.circuit=from THEN zz.h.circuit←to; ENDLOOP;
circuitCount←circuitCount-1;
END;
END;
AddPath:PROCEDURE[a,b:PlacePtr]=BEGIN
vert:BOOLEAN=a.pos.x=b.pos.x;
hor:BOOLEAN=a.pos.y=b.pos.y;
gridlink:GridPtr←AllocateGrid[];
gridlist:GridListPtr←AllocateList[];
IF hor=vert THEN Error;
IF IF vert THEN a.pos.y>b.pos.y ELSE a.pos.x>b.pos.x
THEN {t:PlacePtr←a; a←b; b←t};
gridlink.a←a; gridlink.b←b; gridlink.hor←hor;
gridlist↑←[gridlink,links];
links←gridlist;
DebugPath[a,b];
END;
-- PROCESS GRID
links:GridListPtr←NIL;
ScavengeLinks:PROCEDURE=BEGIN
UNTIL links=NIL DO
pl:GridListPtr←links;
links←pl.t;
FreeGrid[pl.h];
FreeList[pl];
ENDLOOP;
END;
DoUsed:PROCEDURE[r:RectanglePtr]=BEGIN
IF r=NIL OR r.usedCircuit=thisCircuit THEN RETURN;
r.used←r.used+1;
IF r.used>r.avail THEN Log[];
r.usedCircuit←thisCircuit;
END;
SetAboveAndBelowAndUsed:PROCEDURE=BEGIN
FOR gl:GridListPtr←links,gl.t UNTIL gl=NIL DO
grid:GridPtr=gl.h;
a:PlacePtr=grid.a;
hor:BOOLEAN=grid.hor;
ax:Lambda←a.pos.x; ay:Lambda←a.pos.y;
IF hor THEN {DoUsed[a.ue]; DoUsed[a.uw]} ELSE {DoUsed[a.un]; DoUsed[a.us]};
IF hor THEN BEGIN
FOR cl:RectangleListPtr←channels,cl.t UNTIL cl=NIL DO
rect:RectanglePtr=cl.h;
x1:Lambda=rect.pos.x;
y1:Lambda=rect.pos.y;
x2:Lambda=x1+rect.sizeL.x;
y2:Lambda=y1+rect.sizeL.y;
IF ax NOT IN [x1..x2) THEN LOOP;
SELECT ay FROM
y1 =>{grid.above.channel←rect; IF grid.below#nilG THEN EXIT};
y2 =>{grid.below.channel←rect; IF grid.above#nilG THEN EXIT};
IN (y1..y2)=>{grid.below.channel←grid.above.channel←rect; EXIT};
ENDCASE;
ENDLOOP;
FOR il:RectangleListPtr←inters,il.t UNTIL il=NIL DO
rect:RectanglePtr=il.h;
x1:Lambda=rect.pos.x;
y1:Lambda=rect.pos.y;
x2:Lambda=x1+rect.sizeL.x;
y2:Lambda=y1+rect.sizeL.y;
IF ax NOT IN [x1..x2) THEN LOOP;
SELECT ay FROM
y1 =>{grid.above.inter←rect; IF grid.below#nilG THEN EXIT};
y2 =>{grid.below.inter←rect; IF grid.above#nilG THEN EXIT};
ENDCASE;
ENDLOOP;
END ELSE BEGIN
FOR cl:RectangleListPtr←channels,cl.t UNTIL cl=NIL DO
rect:RectanglePtr=cl.h;
x1:Lambda=rect.pos.x;
y1:Lambda=rect.pos.y;
x2:Lambda=x1+rect.sizeL.x;
y2:Lambda=y1+rect.sizeL.y;
IF ay NOT IN [y1..y2) THEN LOOP;
SELECT ax FROM
x2 =>{grid.above.channel←rect; IF grid.below#nilG THEN EXIT};
x1 =>{grid.below.channel←rect; IF grid.above#nilG THEN EXIT};
IN (x1..x2)=>{grid.below.channel←grid.above.channel←rect; EXIT};
ENDCASE;
ENDLOOP;
FOR il:RectangleListPtr←inters,il.t UNTIL il=NIL DO
rect:RectanglePtr=il.h;
x1:Lambda=rect.pos.x;
y1:Lambda=rect.pos.y;
x2:Lambda=x1+rect.sizeL.x;
y2:Lambda=y1+rect.sizeL.y;
IF ay NOT IN [y1..y2) THEN LOOP;
SELECT ax FROM
x2 =>{grid.above.inter←rect; IF grid.below#nilG THEN EXIT};
x1 =>{grid.below.inter←rect; IF grid.above#nilG THEN EXIT};
ENDCASE;
ENDLOOP;
END;
ENDLOOP;
END;
SetHiAndLo:PROCEDURE=BEGIN
FOR gl:GridListPtr←links,gl.t UNTIL gl=NIL DO
grid:GridPtr=gl.h;
grid.hi←grid.above=nilG;
grid.lo←grid.below=nilG;
IF grid.hi AND grid.lo THEN Log[];
ENDLOOP;
SimpleStraightCase[];
DO
progress:BOOLEAN←FALSE;
FOR gl:GridListPtr←links,gl.t UNTIL gl=NIL DO
grid:GridPtr=gl.h;
IF ~grid.hi AND ~grid.lo THEN BEGIN
IF grid.above.channel=NIL THEN grid.hi←TRUE ELSE grid.lo←TRUE;
progress←TRUE;
SimpleStraightCase[];
END;
ENDLOOP;
IF ~progress THEN EXIT;
ENDLOOP;
FOR gl:GridListPtr←links,gl.t UNTIL gl=NIL DO
grid:GridPtr=gl.h;
IF grid.hi = grid.lo THEN Log[];
ENDLOOP;
END;
SimpleStraightCase:PROCEDURE=BEGIN
DO
progress:BOOLEAN←FALSE;
FOR gl:GridListPtr←links,gl.t UNTIL gl=NIL DO
grid:GridPtr=gl.h;
an1,an2,an3,bn1,bn2,bn3,try:GridPtr;
hi:BOOLEAN=grid.hi;
lo:BOOLEAN=grid.lo;
IF hi OR lo THEN LOOP;
[an1,an2,an3,bn1,bn2,bn3]←Neighbors[grid];
SELECT TRUE FROM
an2=NIL AND an1#NIL AND an1.hor=grid.hor=>try←an1;
bn2=NIL AND bn1#NIL AND bn1.hor=grid.hor=>try←bn1;
ENDCASE=>LOOP;
SELECT TRUE FROM
try.hi =>grid.hi←progress←TRUE;
try.lo =>grid.lo←progress←TRUE;
ENDCASE
ENDLOOP;
IF ~progress THEN EXIT;
ENDLOOP;
END;
MakePathFromLinks:PROCEDURE=BEGIN
path1,path2:PathPtr;
IF links=NIL THEN RETURN;
[path1,,]←Foo[FALSE,links.h];
[path2,,]←Foo[TRUE,links.h];
Tie[path1,path2,IF links.h.hor THEN e ELSE n];
END;
Foo:PROCEDURE[bEnd:BOOLEAN,key:GridPtr]
RETURNS[path:PathPtr,orient:Side,hi:BOOLEAN]=BEGIN
eee:Side=IF key.hor THEN IF bEnd THEN e ELSE w ELSE IF bEnd THEN n ELSE s;
www:Side=IF key.hor THEN IF bEnd THEN w ELSE e ELSE IF bEnd THEN s ELSE n;
sss:Side=IF key.hor THEN s ELSE e;
nnn:Side=IF key.hor THEN n ELSE w;
rev:BOOLEAN=key.hor=bEnd;
north:Side=IF key.hi THEN nnn ELSE sss;
Bungle2:PROCEDURE=BEGIN
IF rev=hi1 OR orient1=eee
THEN SELECT TRUE FROM
orient1=eee AND hi1=hi=> Tie[path,path1,eee];
orient1#eee AND orient1#north=> Tie[path,path1,eee];
orient1#eee=>Corner[key,path,path1,eee,orient1];
ENDCASE=>Corner[key,path,path1,eee,north]
ELSE SELECT TRUE FROM
orient1#north=> Tie[path,path1,eee];
ENDCASE=>Tie[Extend[eee,path,link],path1,orient1];
END;
Bungle3:PROCEDURE=BEGIN
swap:BOOLEAN=orient2=eee OR orient1=sss;
IF orient1=orient2 THEN Error;
IF swap THEN BEGIN
{t:PathPtr←path1; path1←path2; path2←t};
{t:Side←orient1; orient1←orient2; orient2←t};
{t:BOOLEAN←hi1; hi1←hi2; hi2←t};
END;
BEGIN
sh:BOOLEAN=(orient2=sss)=hi;
hb2:BOOLEAN=(hi2=rev);
nn:Side←IF orient2=sss THEN nnn ELSE sss;
ss:Side←IF orient2=sss THEN sss ELSE nnn;
IF orient1=eee THEN SELECT TRUE FROM
(hi=hi1) AND hb2=>{Tie[path,path1,eee]; Tie[path2,path1,nn]};
(hi=hi1) AND ~hb2=>{Tie[path,path1,eee]; Tie[path2,path,nn]};
sh AND hb2=>{Tie[path,path2,eee]; Tie[path2,path1,nn]};
~sh AND ~hb2=>{Tie[path,path2,ss]; Tie[path2,path1,eee]};
sh AND ~hb2=>{Tie[path,path2,ss]; Corner[key,path,path1,eee,nn]};
~sh AND hb2=>{Tie[path1,path2,ss]; Corner[key,path,path1,eee,ss]};
ENDCASE=>Error
ELSE BEGIN
Tie[path,IF hi THEN path2 ELSE path1,eee];
SELECT TRUE FROM
hi1=hi2=>Tie[path2,path1,nnn];
~hi AND hb2=>Corner[key,path1,path2,eee,sss];
hi AND ~hb2=>Corner[key,path2,path1,eee,nnn];
~hi AND ~hb2=>Tie[path,path2,sss];
hi AND hb2=>Tie[path,path1,nnn];
ENDCASE=>Error;
END;
END; END;
Bungle4:PROCEDURE=BEGIN
new:PathPtr;
DO SELECT orient1 FROM
nnn=>{IF orient2=sss THEN BEGIN
{t:PathPtr←path3; path3←path2; path2←t};
{t:Side←orient3; orient3←orient2; orient2←t};
{t:BOOLEAN←hi3; hi1←hi3; hi2←t}; END; EXIT};
sss=>BEGIN
{t:PathPtr←path1; path1←path3; path3←t};
{t:Side←orient1; orient1←orient3; orient3←t};
{t:BOOLEAN←hi1; hi1←hi3; hi3←t};
END;
eee=>Error;
ENDCASE=>BEGIN
{t:PathPtr←path1; path1←path2; path2←t};
{t:Side←orient1; orient1←orient2; orient2←t};
{t:BOOLEAN←hi1; hi1←hi2; hi2←t};
END;
ENDLOOP;
new←IF hi1 AND hi3 THEN path ELSE Extend[eee,path,link];
Tie[IF hi3 THEN path2 ELSE new,path3,sss];
Tie[IF hi1 THEN path2 ELSE new,path3,nnn];
SELECT TRUE FROM
hi=hi2=>Tie[new,path2,eee];
hi AND hi3=>Tie[new,path3,eee];
hi AND ~hi1=>Tie[path1,path2,eee];
~hi AND hi1=>Tie[new,path1,eee];
~hi AND ~hi3=>Tie[path3,path2,eee];
ENDCASE=>Corner[key,new,path2,eee,IF hi THEN nnn ELSE sss];
END;
link:Link=IF key.hi THEN key.below ELSE key.above;
an1,an2,an3,bn1,bn2,bn3:GridPtr;
hi1,hi2,hi3:BOOLEAN;
path1,path2,path3:PathPtr←NIL;
orient1,orient2,orient3:Side←x;
place:PlacePtr=IF bEnd THEN key.b ELSE key.a;
rect:RectanglePtr=IF link.channel#NIL THEN link.channel ELSE link.inter;
IF rect=NIL THEN RETURN[NIL,x,TRUE];
BEGIN
pos:CoordL=rect.pos;
size:CoordL=rect.sizeL;
entry:BOOLEAN←IF key.hor
THEN place.pos.x IN (pos.x..pos.x+size.x-1)
ELSE place.pos.y IN (pos.y..pos.y+size.y-1);
[an1,an2,an3,bn1,bn2,bn3]←Neighbors[key];
path←MakePath[link];
orient←eee;
hi←key.hi;
IF bEnd THEN BEGIN
IF bn1#NIL THEN [path1,orient1,hi1]←Foo[key.b=bn1.a,bn1];
IF bn2#NIL THEN [path2,orient2,hi2]←Foo[key.b=bn2.a,bn2];
IF bn3#NIL THEN [path3,orient3,hi3]←Foo[key.b=bn3.a,bn3];
END
ELSE BEGIN
IF an1#NIL THEN [path1,orient1,hi1]←Foo[key.a=an1.a,an1];
IF an2#NIL THEN [path2,orient2,hi2]←Foo[key.a=an2.a,an2];
IF an3#NIL THEN [path3,orient3,hi3]←Foo[key.a=an3.a,an3];
END;
IF path1#NIL AND orient1=www THEN Error;
IF path2#NIL AND orient2=www THEN Error;
IF path3#NIL AND orient3=www THEN Error;
SELECT TRUE FROM
path1=NIL=>NULL;
path2=NIL=>Bungle2[];
path3=NIL=>Bungle3[];
ENDCASE=>Bungle4[];
BEGIN
c:INTEGER←0;
IF path.n#NIL THEN c←c+1; IF path.s#NIL THEN c←c+1;
IF path.e#NIL THEN c←c+1; IF path.w#NIL THEN c←c+1;
IF c>1 THEN {new:PathPtr←MakePath[link]; Tie[new,path,eee]; path←new;};
IF entry OR key.above.channel#NIL AND key.above.channel=key.below.channel
THEN MakeEntryX[path,link,IF entry THEN north ELSE eee,place];
c←0;
IF path.n#NIL THEN c←c+1; IF path.s#NIL THEN c←c+1;
IF path.e#NIL THEN c←c+1; IF path.w#NIL THEN c←c+1;
IF c>1 THEN {new:PathPtr←MakePath[link]; Tie[new,path,eee]; path←new};
END; END; END;
MakeEntryX:PROCEDURE[path:PathPtr,link:Link,d2:Side,place:PlacePtr]=BEGIN
source:PathPtr;
rect:RectanglePtr=IF link.channel#NIL THEN link.channel ELSE link.inter;
newEvent:EventPtr←FindEntry[rect,place];
IF newEvent=NIL THEN RETURN;
source←MakePath[nilG];
source.index←newEvent;
DO SELECT d2 FROM
n=>IF path.n#NIL THEN path←path.n ELSE EXIT;
s=>IF path.s#NIL THEN path←path.s ELSE EXIT;
e=>IF path.e#NIL THEN path←path.e ELSE EXIT;
ENDCASE=>IF path.w#NIL THEN path←path.w ELSE EXIT;
ENDLOOP;
Tie[path,source,d2];
END;
FindEntry:PROCEDURE[rect:RectanglePtr,place:PlacePtr]
RETURNS[EventPtr]=BEGIN
hor:BOOLEAN=rect.orient=hor;
posG:CoordL←[place.pos.x-rect.pos.x,place.pos.y-rect.pos.y];
where:Where=SELECT TRUE FROM
posG.y=0 => IF hor THEN bottom ELSE left,
posG.x=0 => IF hor THEN left ELSE top,
posG.y=rect.sizeL.y => IF hor THEN top ELSE right,
ENDCASE => IF hor THEN right ELSE bottom;
offset:Lambda←SELECT where FROM
top,bottom=>IF hor THEN posG.x ELSE posG.y,
ENDCASE=>IF ~hor THEN posG.x ELSE posG.y;
IF offset=1 THEN offset←0;
FOR el:EventListPtr←rect.events, el.t UNTIL el=NIL DO
event:EventPtr=el.h;
IF event.circuit=thisCircuit AND
where=event.where AND offset=event.offset THEN RETURN[event];
ENDLOOP;
RETURN[NIL];
END;
Corner:PROCEDURE[key:GridPtr,m,n:PathPtr,f,t:Side]=
BEGIN
bend:Link←Extendable[key,f,f,t];
IF bend#nilG THEN Tie[Extend[f,m,bend],n,t]
ELSE Tie[Extend[t,m,Extendable[key,f,t,t]],n,f];
END;
Extendable:PROCEDURE[gl:GridPtr,d,f,t:Side] RETURNS[Link]=BEGIN
a:PlacePtr=SELECT d FROM e,n=>gl.b, ENDCASE=>gl.a;
pos:CoordL←a.pos;
SELECT d FROM
e=>SELECT f FROM
n=>pos.x←pos.x-1;
s=>{pos.x←pos.x-1; pos.y←pos.y-1};
e=>IF t=n THEN pos.y←pos.y-1;
ENDCASE=>Error;
n=>SELECT f FROM
e=>pos.y←pos.y-1;
w=>{pos.x←pos.x-1; pos.y←pos.y-1};
n=>IF t=e THEN pos.x←pos.x-1;
ENDCASE=>Error;
w=>SELECT f FROM
n=>NULL;
s=>pos.y←pos.y-1;
w=>{pos.x←pos.x-1; IF t=n THEN pos.y←pos.y-1};
ENDCASE=>Error;
s=>SELECT f FROM
e=>NULL;
w=>pos.x←pos.x-1;
s=>{pos.y←pos.y-1; IF t=e THEN pos.x←pos.x-1};
ENDCASE=>Error;
ENDCASE=>Error;
SELECT d FROM e,w=>IF ~gl.hor THEN Error;
ENDCASE=>IF gl.hor THEN Error;
FOR cl:RectangleListPtr←channels,cl.t UNTIL cl=NIL DO
rect:RectanglePtr=cl.h;
IF pos.x IN [rect.pos.x..rect.pos.x+rect.sizeL.x)
AND pos.y IN [rect.pos.y..rect.pos.y+rect.sizeL.y)
THEN RETURN[[channel:rect,inter:NIL]];
ENDLOOP;
FOR il:RectangleListPtr←inters,il.t UNTIL il=NIL DO
rect:RectanglePtr=il.h;
IF pos.x IN [rect.pos.x..rect.pos.x+rect.sizeL.x)
AND pos.y IN [rect.pos.y..rect.pos.y+rect.sizeL.y)
THEN RETURN[[channel:NIL,inter:rect]];
ENDLOOP;
RETURN[nilG];
END;
Tie:PROCEDURE[a,b:PathPtr,d:Side]=BEGIN
IF a.channel#NIL AND b.channel#NIL AND a.channel#b.channel THEN Log[];
SELECT d FROM
n=>IF a.n#b.s THEN Log[]; s=>IF a.s#b.n THEN Log[];
e=>IF a.e#b.w THEN Log[]; w=>IF a.w#b.e THEN Log[];
ENDCASE=>Error;
SELECT d FROM
n=>{a.n←b; b.s←a}; s=>{a.s←b; b.n←a};
e=>{a.e←b; b.w←a}; w=>{a.w←b; b.e←a};
ENDCASE=>Error;
END;
Extend:PROCEDURE[dir:Side,old:PathPtr,l:Link] RETURNS[new:PathPtr]=BEGIN
IF l=nilG THEN Error;
new←MakePath[l];
Tie[old,new,dir];
END;
pathNo:INTEGER←0;
MakePath:PROCEDURE[link:Link]
RETURNS[path:PathPtr]=BEGIN
pathList:PathListPtr←AllocateList[];
path←AllocatePath[];
path.channel←link.channel;
path.inter←link.inter;
path.circuit←thisCircuit;
path.pathNo←pathNo←pathNo+1;
pathList↑←[path,allPaths];
allPaths←pathList;
END;
Neighbors:PROCEDURE[grid:GridPtr]
RETURNS[an1,an2,an3,bn1,bn2,bn3:GridPtr]=BEGIN
an1←an2←an3←bn1←bn2←bn3←NIL;
FOR gl2:GridListPtr←links,gl2.t UNTIL gl2=NIL DO
grid2:GridPtr=gl2.h;
SELECT TRUE FROM
grid2=grid=>LOOP;
grid2.a=grid.a OR grid2.b=grid.a=>SELECT TRUE FROM
an1=NIL=>an1←grid2; an2=NIL=>an2←grid2; an3=NIL=>an3←grid2;
ENDCASE=>Error;
grid2.a=grid.b OR grid2.b=grid.b=>SELECT TRUE FROM
bn1=NIL=>bn1←grid2; bn2=NIL=>bn2←grid2; bn3=NIL=>bn3←grid2;
ENDCASE=>Error;
ENDCASE;
ENDLOOP;
END;
DebugPath:PROCEDURE[a,b:PlacePtr]=BEGIN
Return[];
ShowString["make path from "];
ShowPoint[a.pos];
ShowString[" to "];
ShowPoint[b.pos];
ShowDecimal[thisCircuit," circuit "];
END;
from,to:Circuit;
ChangeCircuit:PROCEDURE[p:PlacePtr]=BEGIN
IF p=NIL OR p.circuit#from THEN RETURN;
p.circuit←to;
ChangeCircuit[p.n];
ChangeCircuit[p.s];
ChangeCircuit[p.e];
ChangeCircuit[p.w];
END;
plowOn:BOOLEAN←FALSE;
logs:ARRAY [0..10) OF INTEGER←ALL[0];
Log:PROCEDURE[i:INTEGER←0]=BEGIN
IF i NOT IN [0..10) THEN i←0;
logs[i]←logs[i]+1;
IF ~plowOn THEN Error;
END;
CheckPaths:PROCEDURE=BEGIN
FOR pwl:PathwayListPtr←paths, pwl.t UNTIL pwl=NIL DO
pathway:PathwayPtr=pwl.h;
FOR pl:PathListPtr←pathway.path, pl.t UNTIL pl=NIL DO
path:PathPtr=pl.h;
inter:RectanglePtr=path.inter;
chan:RectanglePtr=path.channel;
IF inter#NIL THEN BEGIN
IF path.n#NIL AND path.n.inter=inter THEN Log[1];
IF path.s#NIL AND path.s.inter=inter THEN Log[1];
IF path.e#NIL AND path.e.inter=inter THEN Log[1];
IF path.w#NIL AND path.w.inter=inter THEN Log[1];
END;
IF chan#NIL AND chan.orient=vert THEN BEGIN
IF (path.n#NIL AND path.n.channel=chan
OR path.s#NIL AND path.s.channel=chan)
AND path.e=NIL AND path.w=NIL THEN Log[3];
IF path.e#NIL THEN SELECT path.e.channel FROM
NIL=>NULL; chan=>IF path.e.index=NIL THEN Log[2]; ENDCASE=>Log[2];
IF path.w#NIL THEN SELECT path.w.channel FROM
NIL=>NULL; chan=>IF path.w.index=NIL THEN Log[2]; ENDCASE=>Log[2];
END;
IF chan#NIL AND chan.orient=hor THEN BEGIN
IF (path.e#NIL AND path.e.channel=chan
OR path.w#NIL AND path.w.channel=chan)
AND path.n=NIL AND path.s=NIL THEN Log[3];
IF path.n#NIL THEN SELECT path.n.channel FROM
NIL=>NULL; chan=>IF path.n.index=NIL THEN Log[2]; ENDCASE=>Log[2];
IF path.s#NIL THEN SELECT path.s.channel FROM
NIL=>NULL; chan=>IF path.s.index=NIL THEN Log[2]; ENDCASE=>Log[2];
END;
ENDLOOP;
ENDLOOP;
END;
ShowPath:PROCEDURE=BEGIN
FOR pl:PathListPtr←allPaths, pl.t UNTIL pl=NIL DO
path:PathPtr=pl.h;
Return[];
ShowPathID[path];
ShowPathID2[" n= ",path.n];
ShowPathID2[" s= ",path.s];
ShowPathID2[" e= ",path.e];
ShowPathID2[" w= ",path.w];
ENDLOOP;
END;
ShowPathID:PROCEDURE[path:PathPtr]=BEGIN
IF path=NIL THEN {ShowString["none "]; RETURN};
ShowDecimal[path.pathNo];
ShowChar[' ];
SELECT TRUE FROM
path.channel#NIL=>ShowDecimal[path.channel.channelNo,"Ch "];
path.inter#NIL=>ShowDecimal[path.inter.channelNo,"Jn "];
path.index#NIL=>ShowString["source"];
ENDCASE=>Log[4];
END;
ShowPathID2:PROCEDURE[s:STRING,path:PathPtr]=BEGIN
ShowString[s];
IF path=NIL THEN ShowString["none "] ELSE ShowDecimal[path.pathNo];
END;
END.
--log 1 = in check, path has not combined inters into one.
--log 2 = in check, connection off the side of a channel.
--log 3 = in check, path has not combined chans into one.
--log 4 = in show, path has no rectangle or source.