--routeSilicon.mesa

DIRECTORY  RouteDefs;

RouteSilicon:PROGRAM IMPORTS RouteDefs EXPORTS RouteDefs =BEGIN
OPEN RouteDefs;

Speed:TYPE=ARRAY [0..9) OF Lambda;
SpeedPtr:TYPE=POINTER TO Speed;

--none of these are true globals, they are just used by everybody.

speed1,speed2,speedy1,speedy2:SpeedPtr;
spaceB,topL:Lambda←0;
Error:SIGNAL=CODE;
wow:INTEGER=1;

-- Main Code

DebugPrint:PROCEDURE=
  {t:BOOLEAN=chipmonk; chipmonk←FALSE; PrintAll[]; chipmonk←t};

DoSilicon:PUBLIC CtlProc=BEGIN
  speed1S, speed2S, speedy1S, speedy2S:Speed;
  speed1←@speed1S;
  speed2←@speed2S;
  speedy1←@speedy1S;
  speedy2←@speedy2S;
  IF layout#NIL THEN Error;
  EnumerateChannels[ChanSilicon];
  EnumerateInters[InterSilicon];
  MakeBlue[];
  ChipmonkSilicon[];
  IF ~ chipmonk THEN PrintAll[];
  IF ~ chipmonk THEN ShowSilicon[];
  RETURN[-1];
  END;

ChanSilicon:PROCEDURE[rect:RectanglePtr]=BEGIN
h:BOOLEAN=rect.orient=hor;
topL←IF h THEN rect.sizeL.y ELSE rect.sizeL.x;
spaceB←IF h THEN rect.margins.s+rect.levelers.s
            ELSE rect.margins.e+rect.levelers.e;
EnumerateRuns[rect,SetRunEnd];
EnumerateRuns[rect,LayRun];
EnumerateConns[rect,LayConn];
END;

SetRunEnd:PROCEDURE[rect:RectanglePtr,run:RunPtr]=BEGIN
x:Lambda=rect.pos.x;
y:Lambda=rect.pos.y;
max:Lambda=IF rect.orient=hor THEN rect.sizeL.x ELSE rect.sizeL.y;
run.startOffX←0;
run.endOffX←max;
IF run.start=-1 THEN BEGIN
  IF rect.nature#culDeSacL THEN run.startOffX←7*run.startOff
  ELSE BEGIN
    e:EventPtr←FindEvent[rect,run];
    u:Lambda=Rot[rect,run.run]; --run
    v:Lambda=Rot[rect,e.offset];  --event
    s:BOOLEAN=e.level#red;
    run.startOffX←IF s AND u=v THEN 0 ELSE 3;
    IF rect.orient=hor THEN BEGIN
      IF s AND u#v THEN MakeBlueWire[TRUE,x,v,6];
      IF ~s THEN {MakeRedWire[TRUE,x,v,5]; MakeContact[x+3,v]};
      IF u#v THEN MakeBlueWire[FALSE,x+3,MIN[u,v],ABS[u-v]+3];
      END
    ELSE BEGIN
      IF s AND u#v THEN MakeBlueWire[FALSE,v,y,6];
      IF ~s THEN {MakeRedWire[FALSE,v,y,5]; MakeContact[v,y+3]};
      IF u#v THEN MakeBlueWire[TRUE,MIN[u,v],y+3,ABS[u-v]+3];
      END;
    END;
  END;
IF run.end  =bigRun THEN BEGIN
  IF rect.nature#culDeSacR THEN run.endOffX  ←max+7*run.endOff
  ELSE BEGIN
    e:EventPtr←FindEvent[rect,run];
    u:Lambda=Rot[rect,run.run]; --run
    v:Lambda=Rot[rect,e.offset];  --event
    s:BOOLEAN=e.level#red;
    run.endOffX←IF s AND u=v THEN max ELSE max-3;
    IF rect.orient=hor THEN BEGIN
      IF s AND u#v THEN MakeBlueWire[TRUE,max-6,v,6];
      IF ~s THEN {MakeRedWire[TRUE,max-5,v,5]; MakeContact[max-7,v]};
      IF u#v THEN MakeBlueWire[FALSE,max-6,MIN[u,v],ABS[u-v]+3];
      END
    ELSE BEGIN
      IF s AND u#v THEN MakeBlueWire[FALSE,v,max-6,6];
      IF ~s THEN {MakeRedWire[FALSE,v,max-5,5]; MakeContact[v,max-7]};
      IF u#v THEN MakeBlueWire[TRUE,MIN[u,v],max-6,ABS[u-v]+3];
      END;
    END;
  END;
IF run.end  =-1 THEN run.endOffX  ←7*run.endOff;
IF run.start=bigRun THEN run.startOffX←max+7*run.startOff;
IF run.start=run.end THEN RETURN;
FOR cl:ConnListPtr←rect.conns,cl.t UNTIL cl=NIL DO
    conn:ConnPtr=cl.h;
    d:Lambda=conn.lambdaX;
    SELECT TRUE FROM
    conn.circuit#run.circuit => LOOP;
    conn.event=-1 => LOOP;
    conn.event=bigRun => LOOP;
    conn.event=run.start =>run.startOffX←d;
    conn.event=run.end =>run.endOffX←d;
    ENDCASE=>LOOP;
    IF run.run NOT IN (conn.start.. conn.end) THEN LOOP;
    IF rect.orient=hor
      THEN MakeContact[x+d,Rot[rect,run.run]]
      ELSE MakeContact[Rot[rect,run.run]+wow,y+d];
    ENDLOOP;
END;

FindEvent:PROCEDURE[rect:RectanglePtr,run:RunPtr] RETURNS[ans:EventPtr]=BEGIN
Sub:PROCEDURE[rect:RectanglePtr,e:EventPtr]=
  {IF (e.where=left OR e.where=right) AND e.circuit=run.circuit THEN ans←e};
ans←NIL;
EnumerateEvents[rect,Sub];
END;

LayRun:PROCEDURE[rect:RectanglePtr,run:RunPtr]=BEGIN
h:BOOLEAN=rect.orient=hor;
x:Lambda=IF h THEN rect.pos.x+run.startOffX ELSE Rot[rect,run.run]-3;
y:Lambda=IF h THEN Rot[rect,run.run] ELSE rect.pos.y+run.startOffX;
MakeBlueWire[h, x, y, run.endOffX-run.startOffX+3];
END;

LayConn:PROCEDURE[rect:RectanglePtr,conn:ConnPtr]=BEGIN
h:BOOLEAN=(rect.orient=hor);
Jog:PROCEDURE[wh:Where,yy,d:Lambda] RETURNS[new:Lambda]=BEGIN
  new←yy;
  IF  wh=bottom AND conn.start#-1 OR wh=top AND conn.end#bigRun
  THEN BEGIN
    xt1:Lambda=IF h THEN x3 ELSE yy-(w+1);
    yt1:Lambda=IF h THEN yy ELSE x3;
    IF conn.level=red THEN MakeContact[xt1,yt1];
    END 
  ELSE BEGIN
    c2:EventPtr=IF ce.where=wh THEN ce ELSE ce.opposite;
    x2:Lambda=(IF h THEN rect.pos.x ELSE rect.pos.y)+c2.offset;
    t:Lambda=ABS[x3-x2];
    IF t=0 THEN RETURN;
    new←yy+d;
    BEGIN
    xt1:Lambda=IF h THEN MIN[x2,x3] ELSE new-w;
    yt1:Lambda=IF h THEN new ELSE MIN[x2,x3];
    xt2:Lambda=IF h THEN x2 ELSE MIN[new-w,yy];
    yt2:Lambda=IF h THEN MIN[new,yy] ELSE x2;
    doOne[ h,xt1,yt1,t+w];
    doOne[~h,xt2,yt2,w2];
    END; END;
  END;
ce:EventPtr=conn.eventPtr;
w:Lambda=IF conn.level=blue THEN 3 ELSE 2;
w2:Lambda=w+w;
doOne:DoOne=IF conn.level=blue THEN MakeBlueWire ELSE MakeRedWire;
x3:Lambda=(IF h THEN rect.pos.x ELSE rect.pos.y)+conn.lambdaX;
ys:Lambda=Jog[bottom,Rot[rect,conn.start],IF h THEN w ELSE -w];
ye:Lambda=Jog[top   ,Rot[rect,conn.end]  ,IF h THEN -w2 ELSE w2];
doOne[~h,IF h THEN x3 ELSE ye,IF h THEN ys ELSE x3,ABS[ye-ys]]
END;

DoOne:TYPE=PROCEDURE[hor:BOOLEAN,x,y,l:Lambda];

ChipmonkSilicon:PROCEDURE=BEGIN
Sub:PROCEDURE[s:SiliconPtr]=BEGIN
  h:Lambda=s.pos2.y-s.pos.y;
  w:Lambda=s.pos2.x-s.pos.x;
  hor:BOOLEAN=h<4;
  l:Lambda=IF hor THEN w ELSE h;
  SELECT s.level FROM
    blue=>PlotBlueWire[hor,s.pos.x,s.pos.y,l];
    red=>PlotRedWire[hor,s.pos.x,s.pos.y,l];
    both=>PlotBlueRedContact[s.pos.x,s.pos.y];
    ENDCASE;
  END;
IF ~chipmonk THEN RETURN;
EnumerateCells[PlotCell];
StartPlot[];
EnumerateSilicon[Sub];
EndPlot[];
END;

PrintAll:PROCEDURE=BEGIN
ShowLabel[" ALL"];
EnumerateChannels[RectanglePrint];
EnumerateInters[RectanglePrint];
END;

RectanglePrint:PROCEDURE[rect:RectanglePtr]=BEGIN
Return[];
Return[];
ShowDecimal[rect.channelNo,"ch "];
ShowPoint[" pos ",rect.pos.x,rect.pos.y];
ShowPoint[" sizeL ",rect.sizeL.x,rect.sizeL.y];
ShowPoint[" sizeC ",rect.sizeC.x,rect.sizeC.y];
ShowString[SELECT rect.orient FROM hor=>" H ", vert=>" V ",
    inter=> "INT ", ENDCASE=>" X "];
ShowString[SELECT rect.nature FROM channel=>" CH ", inter=>" IN ",
    culDeSacR=> " CR ", culDeSacL=> " CL ", 
    bend5=> " B5 ", bend9=> " B9 ", bend6=> " B6 ", bend10=> " B10 ", 
    wallL=> " WL ", wallR=> " WR ", 
    ENDCASE=>" X "];
FOR rl:RunListPtr←rect.runs,rl.t UNTIL rl=NIL DO
  run:RunPtr=rl.h;
  Return[];
  ShowDecimal[run.circuit,"  cir  "];
  ShowDecimal[run.run,"  run  "];
  ShowPoint["  ",run.start,run.end];
  ShowPoint["  ",run.startOff,run.endOff];
  ShowPoint["  ",run.startOffX,run.endOffX];
  ENDLOOP;
FOR cl:ConnListPtr←rect.conns,cl.t UNTIL cl=NIL DO
  conn:ConnPtr=cl.h;
  Return[];
  ShowDecimal[conn.circuit,"  cir  "];
  ShowDecimal[ conn.event,"  conn  "];
  ShowDecimal[conn.lambdaX,"  "];
  ShowPoint["  ",conn.start,conn.end];
  ShowString[SELECT conn.level FROM red=>" r ", blue=>" b ", ENDCASE=>" x "];
  ShowDecimal[conn.offset,"  offset  "];
  ShowString[" "];
  ShowString[SELECT conn.startKind FROM left=>"l", right=>"r", ENDCASE=>"x"];
  ShowString[SELECT conn.endKind FROM left=>"l", right=>"r", ENDCASE=>"x"];
  ENDLOOP;
FOR el:EventListPtr←rect.events,el.t UNTIL el=NIL DO
  event:EventPtr=el.h;
  Return[];
  ShowDecimal[event.circuit,"  cir  "];
  ShowDecimal[event.index,"  event  "];
  ShowString[SELECT event.where FROM top=>" top ", left=>"left",
             right=>"right", ENDCASE=>" bot "];
  ShowDecimal[event.offset,"  offset  "];
  ShowString[SELECT event.level FROM red=>" r ", blue=>" b ", ENDCASE=>" x "];
  ShowString[IF event.opposite=NIL THEN " lone " ELSE " pair "];
  ENDLOOP;
Return[];
ShowDecimal[rect.nw, " nw "];
ShowDecimal[rect.sw, " sw "];
ShowDecimal[rect.ne, " ne "];
ShowDecimal[rect.se, " se "];
ShowDecimal[rect.en, " en "];
ShowDecimal[rect.wn, " wn "];
ShowDecimal[rect.es, " es "];
ShowDecimal[rect.ws, " ws "];
Return[];
ShowDecimal[rect.levelers.n, "levelersN "];
ShowDecimal[rect.levelers.s, " levelersS "];
ShowDecimal[rect.levelers.e, " levelersE "];
ShowDecimal[rect.levelers.w, " levelersW "];
Return[];
ShowDecimal[rect.margins.n, "marginsN "];
ShowDecimal[rect.margins.s, " marginsS "];
ShowDecimal[rect.margins.e, " marginsE "];
ShowDecimal[rect.margins.w, " marginsW "];
Return[];
ShowDecimal[rect.used, "used "];
ShowDecimal[rect.avail, " avail "];
ShowDecimal[rect.usedCircuit, " usedCircuit "];
END;

ShowSilicon:PROCEDURE=BEGIN
offset:CARDINAL←0;
oldLine:STRING←[200];
newLine:STRING←[200];
printLine:STRING←[80];
IF chipmonk THEN RETURN[];
PrintSilicon[];
FOR section:INTEGER IN [0..2) DO
  y:Lambda←problem.chipSize.y;
  seen:INTEGER←0;
  oldLine[0]←'M;--make it change!
  Return[];
  Return[];
--  FindSpeedx[];
  FindSpeedy[];
  DO
    y←y-1;
    IF y<0 THEN EXIT;
    FOR kkk:INTEGER IN [0..LENGTH[speedy1↑])
      DO IF y=speedy1[kkk] THEN {y←y-speedy2[kkk]; EXIT}; ENDLOOP;
    MakeNewLine[newLine,y];
    seen←IF SameString[newLine,oldLine] THEN seen+1 ELSE 0;
    IF seen=0 THEN BEGIN
      s:CARDINAL←newLine.length-offset;
      IF newLine.length<=offset THEN {IF section=0 THEN Error ELSE RETURN};
      printLine.length←MIN[80,s];
      FOR j:CARDINAL IN [0..80) DO printLine[j]←newLine[offset+j]; ENDLOOP;
      END;
    IF seen<6 THEN BEGIN
      Return[];
      ShowString[printLine];
      END;
    {temp:STRING←oldLine; oldLine←newLine; newLine←temp};
    ENDLOOP;
  offset←offset+80;
  ENDLOOP;
END;

PrintSilicon:PROCEDURE=BEGIN
ShowLabel["SILICON"];
FOR sl:SiliconListPtr←layout,sl.t UNTIL sl=NIL
  DO Return[]; ShowWire[sl.h]; ENDLOOP;
END;

FindSpeedy:PROCEDURE=BEGIN
run:INTEGER←0;
speedy1↑←ALL[0]; speedy2↑←ALL[0];
FOR yy:Lambda IN [0..problem.chipSize.y) DO
  hit:BOOLEAN←yy>problem.chipSize.y-6;
  FOR cl:CellListPtr←problem.cells,cl.t UNTIL cl=NIL DO
    c:CellPtr=cl.h;
    IF c.pos.y-yy IN [0..6) OR c.pos.y+c.sizeL.y-yy IN [0..6) THEN hit←TRUE;
    ENDLOOP;
  FOR sl:SiliconListPtr←layout,sl.t UNTIL sl=NIL DO
    s:SiliconPtr=sl.h;
    IF s.pos.y-yy IN [0..6) OR s.pos2.y-yy IN [0..6) THEN hit←TRUE;
    ENDLOOP;
  IF hit AND run#0 THEN BEGIN
    start:INTEGER←yy-1;
    FOR kkk:INTEGER IN [0..LENGTH[speedy1↑]) DO
      IF run>speedy2[kkk] THEN BEGIN
        {t:INTEGER←speedy2[kkk]; speedy2[kkk]←run; run←t};
        {t:INTEGER←speedy1[kkk]; speedy1[kkk]←start; start←t};
        END;
      ENDLOOP;
    END;
  run←IF hit THEN 0 ELSE run+1;
  ENDLOOP;
END;

MakeNewLine:PROCEDURE[s:STRING,y:Lambda]=BEGIN
i:CARDINAL←0;
run:INTEGER←0;
x:Lambda←-1;
topy:Lambda=problem.chipSize.y-1;
Clear[s];
IF y=topy THEN {speed1↑←ALL[0]; speed2↑←ALL[0]};
DO
  hit:BOOLEAN←FALSE;
  what:CHARACTER←' ;
  x←x+1;
  IF x>=problem.chipSize.x THEN EXIT;
  FOR kkk:INTEGER IN [0..LENGTH[speed1↑])
    DO IF x=speed1[kkk] THEN {x←x+speed2[kkk]; EXIT}; ENDLOOP;
  FOR cl:CellListPtr←problem.cells,cl.t UNTIL cl=NIL DO
    cell:CellPtr=cl.h;
    IF x IN [cell.pos.x..cell.pos.x+cell.sizeL.x)
      AND y IN [cell.pos.y..cell.pos.y+cell.sizeL.y) THEN what←'C;
    IF x-cell.pos.x IN [0..6) OR x-cell.pos.x-cell.sizeL.x IN [0..6)
       THEN hit←TRUE;
    ENDLOOP;
  FOR sl:SiliconListPtr←layout,sl.t UNTIL sl=NIL DO
    silicon:SiliconPtr=sl.h;
    IF x-silicon.pos.x IN [0..6) OR x-silicon.pos2.x IN [0..6)
       THEN hit←TRUE;
    IF x IN [silicon.pos.x..silicon.pos2.x)
      AND y IN [silicon.pos.y..silicon.pos2.y) THEN
      what←IF silicon.level=both THEN 'x ELSE SELECT what FROM
        ' =>IF silicon.level=red THEN 'r ELSE 'b,
        'r=>IF silicon.level=red THEN 'r ELSE 'o,
        'b=>IF silicon.level=red THEN 'o ELSE 'b,
        'o=>'o, 'x=>'x, 'C=>'C,
        ENDCASE=>ERROR;
    ENDLOOP;
  IF hit THEN BEGIN
    s[i]←what;
    s.length←i←i+1;
    IF i>=s.maxlength THEN RETURN;
    IF y=topy AND run#0 THEN BEGIN
      start:INTEGER←x-run;
      FOR kkk:INTEGER IN [0..LENGTH[speed1↑]) DO
      IF run>speed2[kkk] THEN BEGIN
        {t:INTEGER←speed2[kkk]; speed2[kkk]←run; run←t};
        {t:INTEGER←speed1[kkk]; speed1[kkk]←start; start←t};
        END;
      ENDLOOP;
      END;
    run←0;
    END
  ELSE run←run+1;
  ENDLOOP;
END;

-- Utilities

Rot:PROCEDURE[rect:RectanglePtr,run:RunNo] RETURNS[z:Lambda]=BEGIN
del:Lambda=Across[run];
z←IF rect.orient=hor THEN rect.pos.y+del ELSE rect.pos.x+rect.sizeL.x-del;
END;

Across:PROCEDURE[run:RunNo] RETURNS[Lambda]=BEGIN
IF run=bigRun THEN RETURN[topL];
IF run=-1 THEN RETURN[0];
RETURN[7*run+spaceB];
END;

MakeBlueWire:PUBLIC PROCEDURE[hor:BOOLEAN,x,y,l:Lambda]=BEGIN
IF l=0 THEN RETURN ELSE BEGIN
s:SiliconPtr←AddSilicon[];
IF l<0 THEN {IF hor THEN x←x+l ELSE y←y+l; l←-l};
s.level←blue;
s.pos←[x,y];
s.pos2←IF hor THEN [x+l,y+3] ELSE [x+3,y+l];
END; END;

MakeRedWire:PUBLIC PROCEDURE[hor:BOOLEAN,x,y,l:Lambda]=BEGIN
IF l=0 THEN RETURN ELSE BEGIN
s:SiliconPtr←AddSilicon[];
IF l<0 THEN {IF hor THEN x←x+l ELSE y←y+l; l←-l};
s.level←red;
s.pos←[x,y];
s.pos2←IF hor THEN [x+l,y+2] ELSE [x+2,y+l];
END; END;

MakeContact:PUBLIC PROCEDURE[x,y:Lambda]=BEGIN
s:SiliconPtr←AddSilicon[];
s.level←both;
s.pos←[x,y];
s.pos2←[x+4,y+4];
END;

AddSilicon:PROCEDURE RETURNS[s:SiliconPtr]=BEGIN
list:SiliconListPtr←AllocateList[];
s←AllocateSilicon[];
list↑←[s,layout];
layout←list;
END;

--known Join Types:
-- 1 = straight through
-- 2 = up 2 then jog right 6 then proceed up
-- 3 = up 2 then jog left 4 then proceed up


END.

FindJoinType:PROCEDURE[rect:RectanglePtr,conn:ConnPtr,side:Side]
  RETURNS[JoinType]
=BEGIN
SELECT side FROM
   n,w=>IF conn.end#bigRun THEN Error;
   s,e=>IF conn.start#-1 THEN Error;
   ENDCASE;
IF conn.offset NOT IN [-1..1] THEN {Error; RETURN[0]};
RETURN[SELECT conn.offset FROM -1=>3, 0=>1, 1=>2, ENDCASE=>ERROR];
END;