--routeCrosses.mesa DIRECTORY RouteDefs; RouteCrosses:PROGRAM IMPORTS RouteDefs EXPORTS RouteDefs =BEGIN OPEN RouteDefs; --the function of Crosses is to fill in the offset field in a Conn record. --this offset will keep cross wires from shorting. --strtKind and endKind are also computed but no one uses them except crosses. Error:SIGNAL=CODE; marginChanged:BOOLEAN; InstallInternalContacts:PUBLIC CtlProc=BEGIN marginChanged_FALSE; EnumerateChannels[MakeOffsets]; IF ~chipmonk THEN EnumerateChannels[ShowCrossesX]; EnumerateChannels[CheckCrosses]; RETURN[IF marginChanged THEN 1 ELSE -1]; END; MakeOffsets:PROCEDURE[rect:RectanglePtr]=BEGIN EnumerateConns[rect,InitConn]; EnumerateConns[rect,OffsetSources]; OffsetJogs[rect,-1]; OffsetJogs[rect,bigRun]; SetRunOffsets[rect]; EnumerateConns[rect,FixJogColor]; EnumerateConns[rect,SetX]; EnumerateConns[rect,CheckMargins]; END; InitConn:PROCEDURE[rect:RectanglePtr,con:ConnPtr]=BEGIN con.startKind_FigureKind[rect,con,con.start]; con.endKind_FigureKind[rect,con,con.end]; IF con.offset#noOffset THEN Error; IF con.lambdaX#-1 THEN Error; END; FigureKind:PROCEDURE[rect:RectanglePtr,con:ConnPtr,where:RunNo] RETURNS[kind:ConnKind]=BEGIN kind_none; IF where=-1 OR where=bigRun THEN RETURN[edge]; FOR rl:RunListPtr_rect.runs, rl.t UNTIL rl=NIL DO run:RunPtr=rl.h; IF ~(con.circuit=run.circuit AND where=run.run) THEN LOOP; IF con.event IN [run.start..run.end) THEN kind_CombineKinds[kind,right]; IF con.event IN (run.start..run.end] THEN kind_CombineKinds[kind,left]; ENDLOOP; IF kind=none THEN SELECT con.event FROM -1=>kind_left; bigRun=>kind_right; ENDCASE=>Error; END; CombineKinds:PROCEDURE[a,b:ConnKind] RETURNS[ConnKind]=BEGIN IF a=edge OR b=edge THEN {Error; RETURN[edge]}; RETURN[IF a=b OR a=none THEN b ELSE IF b=none THEN a ELSE tee] END; OffsetSources:PROCEDURE[rect:RectanglePtr,c:ConnPtr]=BEGIN runMax:INTEGER=rect.sizeC.y; c2,c3:ConnPtr_NIL; tt:ConnPtr=IF c.eventPtr=NIL OR c.eventPtr.opposite=NIL THEN NIL ELSE c.eventPtr.opposite.conn; IF c.offset#noOffset THEN RETURN; IF c.start=-1 THEN IF c.end=bigRun THEN {c.offset_0; RETURN} ELSE {c2_c; c3_tt} ELSE IF c.end=bigRun THEN {c3_c; c2_tt} ELSE RETURN; IF c2#NIL THEN c2.offset_0; IF c3#NIL THEN c3.offset_0; IF c2=c3 THEN Error; IF c2=NIL OR c3=NIL OR c3.start>c2.end THEN RETURN; BEGIN r2:RunNo=IF c2=NIL THEN 0 ELSE IF c2=c3 THEN runMax ELSE c2.end; r3:RunNo=IF c3=NIL THEN runMax ELSE c3.start; r2Gain:RunNo_r2+1; r3Gain:RunNo_runMax-r3; index:INTEGER=(SELECT c2.endKind FROM left=>0,tee=>3,right=>6, ENDCASE=>ERROR) +(SELECT c3.startKind FROM left=>0,tee=>1,right=>2, ENDCASE=>ERROR); FOR rl:RunListPtr_rect.runs,rl.t UNTIL rl=NIL DO r:RunPtr=rl.h; IF c.event NOT IN (r.start..r.end) THEN LOOP; IF r.runr3 THEN r3Gain_MIN[r3Gain,r.run-r3]; ENDLOOP; SELECT index FROM 0=>IF r2Gain>r3Gain THEN c3.offset_-1 ELSE c2.offset_-1; 1=>c3.offset_1; 2=>c3.offset_1; 3=>c2.offset_1; 4=>c2.offset_1;--don't care 5=>c2.offset_-1; 6=>c2.offset_1; 7=>c3.offset_-1; 8=>IF r2Gain>r3Gain THEN c3.offset_1 ELSE c2.offset_1; ENDCASE=>Error; END; END; OffsetJogs:PROCEDURE[rect:RectanglePtr,event:INTEGER]=BEGIN FOR cl:ConnListPtr_rect.conns, cl.t UNTIL cl=NIL DO con:ConnPtr=cl.h; IF con.event#event OR con.offset#noOffset THEN LOOP; FOR j:INTEGER IN [0..1] UNTIL con.offset#noOffset DO this:INTEGER_0; preferR,legalR,emptyR:INTEGER_noOffset; preferL,legalL,emptyL:INTEGER_-noOffset; SELECT con.startKind FROM left,right=>NULL; ENDCASE=>Error; SELECT con.endKind FROM left,right=>NULL; ENDCASE=>Error; FOR w:ConnListPtr_rect.conns, w.t UNTIL w=NIL DO con2:ConnPtr=w.h; plus:BOOLEAN_FALSE; left,right:BOOLEAN_FALSE; off:Lambda=con2.offset; IF con2.event#event OR con2.circuit=con.circuit OR con2.offset=noOffset THEN LOOP; IF con2.start>con.end OR con.start>con2.end THEN LOOP; IF con2.end=con.start THEN {IF con.startKind=right THEN right_TRUE ELSE left_TRUE}; IF con2.start=con.end THEN {IF con.endKind=right THEN right_TRUE ELSE left_TRUE}; SELECT con2.end-con.end FROM 0 =>SELECT con2.start-con.start FROM 0=>left_right_TRUE; ENDCASE=>IF con.endKind=right THEN {right_plus_TRUE} ELSE left_TRUE; >0 =>SELECT con2.start-con.start FROM 0=>IF con.startKind=right THEN {right_plus_TRUE} ELSE left_TRUE; >0=>plus_FALSE; ENDCASE=>plus_off+1<=preferL; ENDCASE=>SELECT con2.start-con.start FROM 0=>IF con.startKind=right THEN {right_plus_TRUE} ELSE left_TRUE; >0=>plus_off+1<=preferL; ENDCASE=>plus_TRUE; IF plus THEN preferL_MAX[off+1,preferL] ELSE preferR_MIN[off-1,preferR]; emptyL_MAX[emptyL,off+1]; emptyR_MIN[emptyR,off-1]; IF right THEN {IF legalL#-noOffset THEN Error ELSE legalL_off+1}; IF left THEN {IF legalR# noOffset THEN Error ELSE legalR_off-1}; ENDLOOP; IF legalL#-noOffset AND legalR#noOffset THEN {SplitConn[rect,event,cl,j]; LOOP}; this_IF legalL#-noOffset OR legalR=noOffset AND (preferL#-noOffset OR preferR=noOffset) THEN MAX[0,emptyL] ELSE MIN[0,emptyR]; IF this NOT IN [legalL..legalR] OR this IN (emptyR..emptyL) THEN Error; con.offset_this; IF this=noOffset OR this=-noOffset THEN Error; IF event=-1 AND this<-1 THEN Error; IF event=-1 AND this<0 THEN MoveConns[rect,event,1]; IF event=bigRun AND this>-1 THEN MoveConns[rect,event,-1]; IF event=bigRun AND this>0 THEN MoveConns[rect,event,-1]; ENDLOOP; ENDLOOP; END; MoveConns:PROCEDURE[rect:RectanglePtr,event,delta:INTEGER]=BEGIN Sub:PROCEDURE[rect:RectanglePtr,c:ConnPtr]= {IF c.event=event AND c.offset#noOffset THEN c.offset_c.offset+delta}; EnumerateConns[rect,Sub]; END; SplitConn:PROCEDURE[rect:RectanglePtr,event:EventNo,cl:ConnListPtr,j:INTEGER]= BEGIN con:ConnPtr=cl.h; yy:RunNo=FindEmptyPlace[rect,event,con.start]; IF yy=-1 OR j=1 THEN {Error; con.offset_0; RETURN}; BEGIN t:BOOLEAN=IF con.startRun=NIL THEN (event=-1) ELSE IF con.endRun=NIL THEN (event#bigRun) ELSE con.startRun.startcon.end THEN SwapEnds[con]; con3.start_yy; con3.startKind_IF con3.endKind=left THEN right ELSE left; IF con3.start>con3.end THEN SwapEnds[con3]; END; END; FindEmptyPlace:PROCEDURE[rect:RectanglePtr,event:EventNo,near:RunNo] RETURNS[RunNo]=BEGIN Try:PROCEDURE[where:RunNo] RETURNS[BOOLEAN]=BEGIN IF where NOT IN [0..rect.sizeC.y) THEN RETURN[FALSE]; FOR rl:RunListPtr_rect.runs,rl.t UNTIL rl=NIL DO r:RunPtr=rl.h; IF r.run=where AND event IN [r.start..r.end] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; END; FOR i:INTEGER IN [0..rect.sizeC.y) DO IF Try[near+i] THEN RETURN[near+i]; IF Try[near-i] THEN RETURN[near-i]; ENDLOOP; RETURN[-1]; END; SwapEnds:PROCEDURE[c:ConnPtr]=BEGIN {t:RunNo=c.start; c.start_c.end; c.end_t}; {q:ConnKind=c.startKind; c.startKind_c.endKind; c.endKind_q}; END; SetRunOffsets:PROCEDURE[rect:RectanglePtr]=BEGIN FOR rl:RunListPtr_rect.runs,rl.t UNTIL rl=NIL DO run:RunPtr=rl.h; run.startOff_run.endOff_0; -- use start and end runs FOR cl:ConnListPtr_rect.conns,cl.t UNTIL cl=NIL DO con:ConnPtr=cl.h; IF con.circuit#run.circuit THEN LOOP; IF run.run#con.start AND run.run#con.end AND (con.event=-1 OR con.event=bigRun) THEN LOOP; IF con.event#run.start AND con.event#run.end THEN LOOP; {end:BOOLEAN=IF run.start#run.end THEN run.end=con.event ELSE (run.run=con.start AND con.startKind=left OR run.run=con.end AND con.endKind=left); IF end THEN run.endOff_con.offset ELSE run.startOff_con.offset}; ENDLOOP; ENDLOOP; END; FixJogColor:PROCEDURE[rect:RectanglePtr,con:ConnPtr]=BEGIN event:EventPtr=con.eventPtr; eventNo:INTEGER=con.event; con.level_blue; con.closeS_con.closeE_FALSE; IF con.start=-1 AND con.end=bigRun AND (event.level=red OR event.opposite.level=red) THEN {con.level_red; RETURN}; IF event#NIL AND event.level=red THEN {con.level_red; RETURN}; FOR rl:RunListPtr_rect.runs,rl.t UNTIL rl=NIL DO run:RunPtr=rl.h; IF run.circuit=con.circuit THEN LOOP; IF run.run NOT IN [con.start..con.end] THEN LOOP; IF eventNo NOT IN [run.start..run.end] THEN LOOP; IF con.offset=0 THEN BEGIN IF eventNo= run.start AND con.offsetrun.endOff THEN LOOP; END; con.level_red; IF con.start=-1 AND run.run=0 AND (event.where=bottom AND event.level=blue OR event.where=top AND event.opposite.level=blue) THEN con.closeS_TRUE; IF con.end=bigRun AND run.run>=rect.sizeC.y-1 AND (event.where=top AND event.level=blue OR event.where=bottom AND event.opposite.level=blue) THEN con.closeE_TRUE; ENDLOOP; END; CheckCrosses:PROCEDURE[rect:RectanglePtr]=BEGIN FOR cl:ConnListPtr_rect.conns,cl.t UNTIL cl=NIL DO con:ConnPtr=cl.h; IF con.offset=noOffset OR con.offset=-noOffset THEN Error; ENDLOOP; END; ShowCrossesX:PROCEDURE[rect:RectanglePtr]=BEGIN Store:PROCEDURE[c:CHARACTER,x:INTEGER]=BEGIN IF x NOT IN [0..line/2) THEN {x_x-limit+line-1; IF x NOT IN [line/2..line) THEN RETURN}; IF c='r AND s[x]#' THEN c_'R; IF c='c THEN {IF s[x]=' THEN c_'b ELSE RETURN}; s[x]_c; END; runMax:INTEGER=rect.sizeC.y; limit:CARDINAL=4+2*runMax; line:CARDINAL=40; limitE:CARDINAL=MAX[limit-1,line/2]; s:STRING_[line]; ShowLabel["CROSSES "]; ShowDecimal[rect.channelNo]; Return[]; FOR i:INTEGER IN [0..rect.sizeC.x] DO max:INTEGER_-noOffset; min:INTEGER_noOffset; FOR cl:ConnListPtr_rect.conns,cl.t UNTIL cl=NIL DO con:ConnPtr=cl.h; IF con.event#i THEN LOOP; max_MAX[max,con.offset]; min_MIN[min,con.offset]; ENDLOOP; FOR z:INTEGER IN [min..max] DO Return[]; Clear[s]; IF z=0 THEN FOR t:EventListPtr_rect.events, t.t UNTIL t=NIL DO e:EventPtr_t.h; IF i # e.index THEN LOOP; IF e.where=top THEN s[line-1]_ShowCircuit[e.circuit]; IF e.where=bottom THEN s[0]_ShowCircuit[e.circuit]; ENDLOOP; FOR cl:ConnListPtr_rect.conns,cl.t UNTIL cl=NIL DO con:ConnPtr=cl.h; stop:INTEGER=IF con.end=bigRun THEN limitE ELSE 2+2*con.end; IF con.event#i OR con.offset#z THEN LOOP; FOR j:[0..10000) IN [2+2*con.start..stop] DO IF ~(j=0 OR j=limit) THEN Store['b,j]; ENDLOOP; ENDLOOP; FOR cl:ConnListPtr_rect.conns,cl.t UNTIL cl=NIL DO con:ConnPtr=cl.h; IF con.event#i OR con.offset=z THEN LOOP; IF con.startKind=tee OR con.startKind=right AND con.offsetz THEN Store['b,2+2*con.start]; IF con.endKind=tee OR con.endKind=right AND con.offsetz THEN Store['b,2+2*con.end]; ENDLOOP; FOR rl:RunListPtr_rect.runs,rl.t UNTIL rl=NIL DO r:RunPtr=rl.h; IF i IN (r.start..r.end) THEN Store['c,2+2*r.run]; ENDLOOP; ShowString[s]; ENDLOOP; Clear[s]; FOR rl:RunListPtr_rect.runs,rl.t UNTIL rl=NIL DO r:RunPtr=rl.h; IF i IN [r.start..r.end) THEN Store['b,2+2*r.run]; ENDLOOP; FOR zz:INTEGER IN [0..3) DO Return[]; ShowString[s]; ENDLOOP; ENDLOOP; END; Convert:PROCEDURE[x:ConnKind] RETURNS[CHARACTER]=BEGIN RETURN[SELECT x FROM tee=>'t, right=>'r, left=>'l, edge=>'e, none=>'x, ENDCASE=>'z]; END; SetX:PROCEDURE[rect:RectanglePtr,c1:ConnPtr]=BEGIN span:Lambda=IF rect.orient=hor THEN rect.sizeL.x ELSE rect.sizeL.y; ok1:PROCEDURE[c:ConnPtr,x:Lambda] RETURNS[BOOLEAN]=BEGIN e1:EventPtr=c.eventPtr; e2:EventPtr=IF e1=NIL THEN NIL ELSE e1.opposite; IF e1=NIL THEN RETURN[TRUE]; IF x NOT IN [0..span) THEN RETURN[FALSE]; RETURN[(e1.next=NIL OR e1.next.offset>x+6) AND (e1.prev=NIL OR e1.prev.offsetx+6 OR Decoupled[c,e2.next.conn]) AND (e2.prev=NIL OR e2.prev.offset=bigRun THEN c1.lambdaX_ (IF rect.orient=hor THEN rect.sizeL.x ELSE rect.sizeL.y) + 7*c1.offset; RETURN; END; BEGIN e1:EventPtr=c1.eventPtr; e2:EventPtr=e1.opposite; IF e2=NIL THEN {c1.lambdaX_e1.offset; RETURN}; BEGIN lSub:PROCEDURE[t:Lambda] RETURNS[b:BOOLEAN]=BEGIN b_ok1[c1,t] AND ok1[c2,t+del]; IF b THEN {c1.lambdaX_t; c2.lambdaX_t+del}; END; c2:ConnPtr=e2.conn; del:Lambda=7*(c2.offset-c1.offset); x1:Lambda=e1.offset; x2:Lambda=e2.offset; xmin:Lambda=MIN[x1,x2]; xmax:Lambda=MAX[x1,x2]; IF Decoupled[c1,c2] THEN BEGIN IF ok1[c1,x1] THEN {c1.lambdaX_x1; IF ok1[c2,x2] THEN c2.lambdaX_x2; RETURN}; FOR t:INTEGER IN [x1-6..x1+6] DO IF ok1[c1,t] THEN {c1.lambdaX_t; RETURN}; ENDLOOP; Error; RETURN; END; IF c1.offset=0 THEN {IF lSub[x1] OR lSub[x2] THEN RETURN} ELSE {IF lSub[x2] OR lSub[x1] THEN RETURN}; FOR t:Lambda IN (xmin..xmax) DO IF lSub[t] THEN RETURN; ENDLOOP; FOR t:Lambda IN [xmin-6..xmin) DO IF lSub[t] THEN RETURN; ENDLOOP; FOR t:Lambda IN (xmax..xmax+6] DO IF lSub[t] THEN RETURN; ENDLOOP; END; END; END; Decoupled:PROCEDURE [c1,c2:ConnPtr] RETURNS[BOOLEAN]= {RETURN[c1.end=rect.sizeC.y-1 THEN BEGIN t:INTEGER_IF con.closeE THEN 9 ELSE 6; IF rect.orient=hor THEN {t_t-rect.levelers.n; IF rect.margins.n