DIRECTORY Basics, CD, CDBasics, CDCells, CDCommandOps, CDCreateLabels, CDDirectory, CDFrame, CDGenerate, CDIO, CDMenus, CDOps, CDOrient, CDPinObjects, CDRects, CDSequencer, CDSil, CDTexts, CMosB, Commander, CommandTool, FS, Imager, ImagerFont, IO, NodeProps, PutGet, PW, PWPins, PWRoute, Real, RedBlackTree, Rope, CDSimpleOps, TerminalIO, TextNode, VFonts, ViewerIO; CDFrameImpl: CEDAR PROGRAM IMPORTS Basics, CD, CDBasics, CDCells, CDCommandOps, CDCreateLabels, CDDirectory, CDFrame, CDIO, CDMenus, CDOps, CDOrient, CDPinObjects, CDRects, CDSequencer, CDSil, CDSimpleOps, CMosB, Commander, CommandTool, FS, ImagerFont, IO, NodeProps, PutGet, PW, PWPins, Real, RedBlackTree, Rope, TerminalIO, VFonts, ViewerIO EXPORTS CDFrame = BEGIN OPEN CDFrame; NewFrame: PUBLIC PROC [size: INT, xory: XorY, name: IO.ROPE, data: REF_NIL, unord: BOOL_FALSE] RETURNS [new: Frame] = { new _ NEW[FrameSeq[size]]; new.xory _ xory; new.data _ data; new.unordered _ unord; new.shell _ NEW[ShellRec _ [name: name]] }; NewExpandFrame: PUBLIC PROC[name: IO.ROPE, proc: ExpandProc] RETURNS [frame: Frame] = { frame _ NEW[FrameSeq[0]]; frame.shell _ NEW[ShellRec _ [name: name]]; IF proc # NIL THEN frame.data _ NEW[ExpandProc _ proc]}; NewObjectFrame: PUBLIC PROC[cell: CD.Object] RETURNS[frame: Frame] = { frame _ NEW[FrameSeq[0]]; frame.data _ cell; frame.shell _ ShellFromObject[cell]}; NewShellFileFrame: PUBLIC PROC[name: IO.ROPE] RETURNS [frame: Frame] = { frame _ NEW[FrameSeq[0]]; frame.shell _ NEW[ShellRec _ [name: name]]; frame.data _ ShellFromFile[name]}; NextIDIndex: INT _ 0; ID: PUBLIC PROC[name: IO.ROPE] RETURNS[unique: IO.ROPE] = { unique _ IO.PutFR["%g%g", IO.rope[name], IO.int[NextIDIndex]]; NextIDIndex _ NextIDIndex+1}; Glue: PUBLIC PROC[ name: IO.ROPE _ NIL, l,r,b,t: GlueSideType _ cap, -- cap conn ext chan sum diff bObj,rObj,tObj,lObj: CD.Object _ NIL, tDir: PWRoute.HorV _ horizontal, -- vertical horizontal tLayer: IO.ROPE _ NIL, -- metal metal2 poly bLayer: IO.ROPE _ NIL, xlate: BOOL _ FALSE ] -- metal2 poly metal RETURNS [new: Frame] = { glue: REF GlueSpec; IF tLayer=NIL THEN tLayer _ IF tDir=horizontal THEN "metal" ELSE "metal2"; IF bLayer=NIL THEN bLayer_IF Rope.Equal[tLayer, "metal"] THEN "metal2" ELSE "metal"; glue _ NEW[GlueSpec _ [ tDir: tDir, type: [b,r,t,l], obj: [bObj,rObj,tObj,lObj], params: NEW[PWRoute.RouterParamsRec _ [trunkLayer: tLayer, branchLayer:bLayer]]]]; SetGlueClass[glue]; IF xlate THEN IF glue.class#ext THEN Signal[] ELSE glue.class _ xlt; IF name=NIL OR name.Length[]=0 THEN name _ SELECT glue.class FROM fill => ID["Fill-"], ext => ID["Ext-"], xlt => ID["Xlt-"], chan => ID["Chan-"], pwr => ID["Pwr-"], sb => ID["SBox-"], ENDCASE => ID["Bad-"]; new _ NewFrame[0, x, name, glue]; new.shell.size _ IF glue.class=chan OR glue.class=pwr THEN WildSize[] ELSE TameSize[]}; font1: Imager.Font _ VFonts.EstablishFont [family:"Helvetica", size: 7, bold: TRUE, italic: FALSE, defaultOnFailure: FALSE]; font2: Imager.Font _ VFonts.EstablishFont [family:"Helvetica", size: 14, bold: TRUE, italic: FALSE, defaultOnFailure: FALSE]; SetGlueClass: PUBLIC PROC[glue: REF GlueSpec] = { OPEN glue; Type: PROC[side: Side] RETURNS[GlueSideType] = { SELECT type[side] FROM pwr => RETURN[conn]; sum, diff => RETURN[chan]; ENDCASE => RETURN[type[side]]}; eqS: BOOL _ (Type[left] = Type[right]) OR (Type[top] = Type[bottom]); cnt: ARRAY GlueSideType OF INT _ ALL[0]; FOR side: Side IN Side DO cnt[type[side]] _ cnt[type[side]] +1; IF type[side]=ext AND type[OppSide[side]]#conn THEN {class _ bad; Signal[]; RETURN} ENDLOOP; IF cnt[pwr]>1 THEN {class _ bad; Signal[]; RETURN}; SELECT (((cnt[conn]+cnt[pwr]) *10 + cnt[ext]) *10 + cnt[cap]) *10 + cnt[chan] + cnt[sum] + cnt[diff] FROM 4000 => {class _ sb}; 3100 => {class _ sb}; 3010 => {class _ sb}; 2200 => {class _ IF eqS THEN bad ELSE sb}; 2110 => {class _ IF eqS THEN bad ELSE sb}; 2020 => {class _ IF ~eqS THEN sb ELSE chan}; 2011 => {class _ IF ~eqS THEN bad ELSE chan}; 2002 => {class _ IF ~eqS THEN bad ELSE chan}; 1120 => {class _ IF ~eqS THEN bad ELSE ext}; 1111 => {class _ chan}; 1102 => {class _ IF ~eqS THEN bad ELSE chan}; 1021 => {class _ IF eqS THEN bad ELSE chan}; 1012 => {class _ IF ~eqS THEN bad ELSE chan}; 0040 => {class _ fill}; 0022 => {class _ IF ~eqS THEN bad ELSE chan}; ENDCASE => {class _ bad}; IF class=chan THEN IF cnt[chan]+cnt[sum]+cnt[diff]=0 THEN {IF (tDir=vertical) = (type[left] = cap AND type[right] = cap) THEN Signal[]} ELSE {IF (tDir=vertical) = (Type[left] = chan OR Type[right] = chan) THEN Signal[]}; IF class=chan AND cnt[pwr]#0 THEN class_pwr; IF class=bad THEN Signal[]}; ScaledText: PUBLIC PROC[design: CD.Design, text: IO.ROPE, box: CD.Position, layer: CD.Layer] RETURNS[cell: CD.Object] = { Scale: PROC[font: Imager.Font] RETURNS[scale: INT] = { extents: ImagerFont.Extents _ ImagerFont.RopeBoundingBox[font, text]; strSize: CD.Position; IF box.x<4 OR box.y<4 THEN RETURN[0]; strSize.x _ Real.RoundI[extents.rightExtent+extents.leftExtent]; strSize.y _ Real.RoundI[extents.ascent+extents.descent]; scale _ MIN[box.x/strSize.x, box.y/strSize.y]}; scaleFactor: INT _ Scale[font2]; IF scaleFactor>0 THEN RETURN[CDCreateLabels.CreateTextCell[design, text, font2, scaleFactor, layer]]; scaleFactor _ Scale[font1]; IF scaleFactor>0 THEN RETURN[CDCreateLabels.CreateTextCell[design, text, font1, scaleFactor, layer]]; RETURN[NIL] }; Log2: PROC [n: INT] RETURNS [INT] = {RETURN [IF n<=1 THEN 0 ELSE 1 + Log2[n / 2]]}; Exp2: PROC [n: INT] RETURNS [INT] = {RETURN [IF n<=0 THEN 1 ELSE 2 * Exp2[n-1]]}; BlankCell: PUBLIC PROC[design: CD.Design, size: CD.Position] RETURNS[cell: CD.Object] ~ { cellPtr: CD.CellPtr; found: BOOL; name: ROPE _ IO.PutFR["Dummy-%g-%g", IO.int[size.x], IO.int[size.y]]; IF size.x=0 OR size.y=0 THEN RETURN[NIL]; [found, cell] _ CDDirectory.Fetch[design, name]; IF found THEN RETURN[cell]; cell _ CDCells.CreateEmptyCell[]; cellPtr _ NARROW[cell.specificRef]; cellPtr.contents _ CONS[NEW[CD.InstanceRep _ [ob: CDRects.CreateRect[size, CD.backGround]] ], cellPtr.contents]; PW.IncludeInDirectory[design, cell, name]}; ShellToBlock: PUBLIC PROC[design: CD.Design, shell: REF ShellRec] RETURNS[block: CD.Object] = { size: CD.Position _ [shell.size.x, shell.size.y]; hor, ver: CD.Object; box: CD.Position; text: CD.Object; layer: CD.Layer; lineScale: INT = 4 ; lwidth: INT _ 1; rotate: BOOL _ FALSE; IF size.x=0 OR size.y=0 THEN RETURN[NIL]; IF size.x IN (0..4*lineScale) OR size.y IN (0..4*lineScale) THEN RETURN[BlankCell[design, size]]; lwidth _ lineScale * MAX[lwidth, MIN[size.x/100, size.y/100]]; box _ [(size.x-4*lwidth), (size.y-4*lwidth)]; IF box.y/box.x > 1 THEN {box _ CD.Position[box.y, box.x]; rotate _ TRUE}; layer _ SELECT design.technology FROM CMosB.cmosB => CMosB.met, CDSil.cdsil => CDSil.xneutral, ENDCASE => ERROR; hor _ CDRects.CreateRect[[size.x, lwidth], layer]; ver _ CDRects.CreateRect[[lwidth, size.y], layer]; block _ CDCells.CreateEmptyCell[]; text _ ScaledText[design, shell.name, box, layer]; IF text#NIL THEN { IF rotate THEN text _ PW.Rot90[design, text]; [ ] _ PW.IncludeInCell[block, text, [(size.x-text.size.x)/2, (size.y-text.size.y)/2]]}; [ ] _ PW.IncludeInCell[block, hor, [0, 0]]; [ ] _ PW.IncludeInCell[block, hor, [0, size.y-lwidth]]; [ ] _ PW.IncludeInCell[block, ver, [0, 0]]; [ ] _ PW.IncludeInCell[block, ver, [size.x-lwidth, 0]]; PW.IncludeInDirectory[design, block, shell.name]}; ShellToObject: PUBLIC PROC[design: CD.Design, shell: REF ShellRec, detailed: BOOL _ TRUE] RETURNS[cell: CD.Object] = { IF design.technology= CDSil.cdsil OR NOT detailed THEN RETURN[ShellToBlock[design, shell]]; FOR side: Side IN Side DO IF shell.pins[side]#NIL THEN EXIT REPEAT FINISHED => RETURN[ShellToBlock[design, shell]] ENDLOOP; cell _ CDCells.CreateEmptyCell[]; FOR side: Side IN Side DO pins: REF PinSeq _ shell.pins[side]; IF pins#NIL THEN FOR i: INT IN [0..pins.seqSize) DO pos: CD.Position _ [pins[i].pos.x-shell.pos.x, pins[i].pos.y-shell.pos.y]; pinApl: CD.Instance _ PW.IncludeInCell [cell, CDPinObjects.CreatePinOb[pins[i].size], pos]; CDPinObjects.SetName[pinApl, pins[i].name]; CDPinObjects.SetLayer[pinApl, pins[i].layer] ENDLOOP; ENDLOOP; CDCells.SetInterestRect[cell, [0, 0, shell.size.x, shell.size.y]]; PW.IncludeInDirectory[design, cell, shell.name]; IF CD.InterestSize[cell]#[shell.size.x, shell.size.y] THEN Signal[]}; IncludePinNamesInBlock: PROC [design: CD.Design, shell: REF ShellRec, block: CD.Object, layer: CD.Layer] = { textOb: CD.Object; FOR side: Side IN Side DO pins: REF PinSeq _ shell.pins[side]; bias: INT = 8; orient: CD.Orientation _ SELECT side FROM left, right => CDOrient.original, top, bottom => CDOrient.rotate90, ENDCASE => ERROR; IF pins#NIL THEN FOR i: INT IN [0..pins.seqSize) DO pos: CD.Position; textOb _ ScaledText[design, pins[i].name, [400, 14], layer]; pos.x _ SELECT side FROM left => pins[i].pos.x + bias, right => pins[i].pos.x + pins[i].size.x - textOb.size.x - bias, bottom => pins[i].pos.x + pins[i].size.x, top => pins[i].pos.x + pins[i].size.x, ENDCASE => ERROR; pos.y _ SELECT side FROM left => pins[i].pos.y, right => pins[i].pos.y, bottom => pins[i].pos.y + bias, top => pins[i].pos.y + pins[i].size.y - textOb.size.x - bias, ENDCASE => ERROR; [ ] _ PW.IncludeInCell[block, textOb, pos, orient]; ENDLOOP ENDLOOP}; CellInDesign: PUBLIC PROC[cell: CD.Object, design: CD.Design] RETURNS[BOOL]= {RETURN[cell#NIL AND cell = CDDirectory.Fetch[design, CDDirectory.Name[cell]].object ]}; ExpandFrame: PUBLIC ExpandProc = { new _ frame; IF new=NIL THEN {Signal[]; RETURN[NIL]}; IF new.seqSize > 0 THEN { FOR index: INT IN [0..new.seqSize) DO new[index] _ ExpandFrame[new[index], design] ENDLOOP} ELSE { IF new.data=NIL THEN {Signal[]; RETURN[new]}; WITH new.data SELECT FROM cell: CD.Object => new.shell _ ShellFromObject[NARROW[new.data]]; shell: REF ShellRec => { frame.shell _ shell; frame.data _ ShellToObject[design, shell, TRUE]}; cellName: IO.ROPE => { cell: CD.Object; found: BOOL; [found, cell] _ CDDirectory.Fetch[design, cellName]; IF found THEN {new.data _ cell; new.shell _ ShellFromObject[cell]} ELSE {Signal[]; new.shell _ ShellFromFile[cellName]} }; proc: REF PROC [design: CD.Design] RETURNS [cell: CD.Object] => { new.data _ proc^[design]; new.shell _ ShellFromObject[NARROW[new.data]]}; proc: REF PW.UserProc => { new.data _ proc^[design, NIL, NIL, NIL]; new.shell _ ShellFromObject[NARROW[new.data]]}; proc: REF ExpandProc => { orient: CD.Orientation _ new.orient; new _ proc^[new, design]; new _ ExpandFrame[new, design]; new.orient _ orient; RETURN[new]}; glue: REF GlueSpec => { log.PutRope["\n Glue Spec expansion delayed: "]; log.PutRope[new.shell.name]; RETURN[new]}; ENDCASE => { log.PutRope["\n Unknown expansion delayed: "]; log.PutRope[new.shell.name]; RETURN[new]}; log.PutRope["\n Expanded frame: "]; log.PutRope[new.shell.name]; IF new.shell.size.x <1 OR new.shell.size.y <1 THEN Signal[]}; RETURN[new]}; DeleteZeroFrames: PUBLIC PROC[frame: Frame] RETURNS[new: Frame] = { IF frame.shell.size.x=0 OR frame.shell.size.y=0 THEN { log.PutRope["\n Deleteing zero sized frame:%"]; log.PutRope[frame.shell.name]; RETURN[NIL]}; IF frame.seqSize = 0 THEN RETURN[frame] ELSE { count: INT _ 0; FOR index: INT IN [0..frame.seqSize) DO frame[index] _ DeleteZeroFrames[frame[index]]; IF frame[index]#NIL THEN count _ count+1; ENDLOOP; IF count = frame.seqSize THEN RETURN[frame]; new _ NEW[FrameSeq[count]]; new.shell _ frame.shell; new.data _ frame.data; new.xory _ frame.xory; new.unordered _ frame.unordered; FOR index: INT DECREASING IN [0..frame.seqSize) DO IF frame[index]=NIL THEN LOOP; count _ count-1; new[count] _ frame[index] ENDLOOP; RETURN[new]}}; ReadShellFrame: PUBLIC SpecificFrameProc = { -- new done _ frame name design IF name=NIL THEN name _ frame.shell.name; IF frame.shell#NIL AND Rope.Equal[frame.shell.name, name] THEN {RETURN[NewShellFileFrame[name], TRUE]}; done _ FALSE; new _ frame; FOR index: INT IN [0..new.seqSize) WHILE NOT done DO [new[index], done] _ ReadShellFrame[new[index], name, design] ENDLOOP}; WriteShellFrame: PUBLIC SpecificFrameProc = { -- new done _ frame name design IF name=NIL THEN name _ frame.shell.name; IF frame.shell#NIL AND Rope.Equal[frame.shell.name, name] THEN {ShellToFile[frame.shell]; RETURN[frame, TRUE]}; done _ FALSE; new _ frame; FOR index: INT IN [0..new.seqSize) WHILE NOT done DO [new[index], done] _ WriteShellFrame[new[index], name, design] ENDLOOP}; FrameToObject: PUBLIC PROC[frame: Frame, design: CD.Design, detailed: BOOL _ TRUE] RETURNS[cell: CD.Object] = { IF design.technology=CMosB.cmosB AND frame.data#NIL AND ISTYPE[frame.data, CD.Object] THEN RETURN[NARROW[frame.data]]; IF frame.seqSize=0 THEN RETURN[ShellToObject[design, frame.shell, detailed]] ELSE { list: PW.ListOb; FOR i: INT DECREASING IN [0..frame.seqSize) DO list _ CONS[FrameToObject[ frame.seq[i],design], list] ENDLOOP; IF frame.xory=x THEN cell _ PW.AbutListX[design, list] ELSE cell _ PW.AbutListY[design, list]; PW.RenameObject[design, cell, frame.shell.name]} }; ReOrient: PUBLIC PROC [frame: Frame, design: CD.Design, orient: CD.Orientation _ CD.original] = { ReSeq: PROC = { TwoFrames: TYPE = RECORD[f0, f1: Frame]; FOR i: INT IN [0..frame.seqSize/2) DO [frame[frame.seqSize-i-1], frame[i]] _ TwoFrames[frame[i], frame[frame.seqSize-i-1]]; ENDLOOP}; yorx: XorY _ IF frame.xory = x THEN y ELSE x; orient _ CDOrient.ComposeOrient[frame.orient, orient]; frame.orient _ CDOrient.original; IF frame.seqSize = 0 THEN { IF orient=CDOrient.original THEN RETURN; IF frame.data= NIL THEN ERROR; WITH frame.data SELECT FROM glue: REF GlueSpec => { OPEN glue; type _ SELECT orient FROM CDOrient.original => [type[bottom], type[right], type[top], type[left]], CDOrient.mirrorX => [type[bottom], type[left], type[top], type[right]], CDOrient.rotate90 => [type[left], type[bottom], type[right], type[top]], CDOrient.rotate90X => [type[left], type[top], type[right], type[bottom]], CDOrient.rotate180 => [type[top], type[left], type[bottom], type[right]], CDOrient.rotate180X => [type[top], type[right], type[bottom], type[left]], CDOrient.rotate270 => [type[right], type[top], type[left], type[bottom]], CDOrient.rotate270X => [type[right], type[bottom], type[left], type[top]], ENDCASE => ERROR; obj _ SELECT orient FROM CDOrient.original => [obj[bottom], obj[right], obj[top], obj[left]], CDOrient.mirrorX => [obj[bottom], obj[left], obj[top], obj[right]], CDOrient.rotate90 => [obj[left], obj[bottom], obj[right], obj[top]], CDOrient.rotate90X => [obj[left], obj[top], obj[right], obj[bottom]], CDOrient.rotate180 => [obj[top], obj[left], obj[bottom], obj[right]], CDOrient.rotate180X => [obj[top], obj[right], obj[bottom], obj[left]], CDOrient.rotate270 => [obj[right], obj[top], obj[left], obj[bottom]], CDOrient.rotate270X => [obj[right], obj[bottom], obj[left], obj[top]], ENDCASE => ERROR; FOR side: Side IN Side DO IF obj[side]#NIL AND type[side]=chan THEN obj[side] _ PW.ChangeOrientation[design, obj[side], orient] ELSE obj[side] _ NIL ENDLOOP; SELECT orient FROM CDOrient.rotate90, CDOrient.rotate90X, CDOrient.rotate270, CDOrient.rotate270X => { temp: IO.ROPE _ params.branchLayer; params.branchLayer _ params.trunkLayer; params.trunkLayer _ temp; frame.shell.size _ FlipSize[frame.shell.size]; tDir _ IF tDir=horizontal THEN vertical ELSE horizontal}; ENDCASE }; cell: CD.Object => { cell _ PW.ChangeOrientation[design, cell, orient]; frame.shell.size _ FixedSize[CD.InterestSize[cell]]; frame.data _ cell}; ENDCASE => ERROR; RETURN}; SELECT orient FROM CDOrient.original => { }; CDOrient.mirrorX => { IF frame.xory=x THEN ReSeq[] }; CDOrient.rotate90 => {frame.xory _ yorx; IF frame.xory=x THEN ReSeq[] }; CDOrient.rotate90X => {frame.xory _ yorx; }; CDOrient.rotate180 => { IF TRUE THEN ReSeq[] }; CDOrient.rotate180X => { IF frame.xory=y THEN ReSeq[] }; CDOrient.rotate270 => {frame.xory _ yorx; IF frame.xory=y THEN ReSeq[] }; CDOrient.rotate270X => {frame.xory _ yorx; IF TRUE THEN ReSeq[] }; ENDCASE; FOR i: INT IN [0..frame.seqSize) DO ReOrient[frame[i], design, orient] ENDLOOP}; ObjSize: PUBLIC PROC[ob: CD.Object] RETURNS[size: CD.Position] = {RETURN[CD.InterestSize[ob]]}; GetSize: PUBLIC PROC[frame: Frame] = { variable: BOOL _ FALSE; dad, son: Size; IF frame.seqSize = 0 THEN { IF frame.data=NIL THEN {Signal[]; RETURN}; WITH frame.data SELECT FROM cell: CD.Object => {frame.shell.size _ FixedSize[CD.InterestSize[cell]]}; glue: REF GlueSpec => { frame.shell.size _ TameSize[]; IF glue.class=chan OR glue.class=pwr THEN IF glue.tDir=vertical THEN frame.shell.size.xfree _ wild ELSE frame.shell.size.yfree _ wild}; ENDCASE => ERROR; IF frame.shell.size.x < 1 OR frame.shell.size.y < 1 THEN {Signal[]; frame.data _ NIL}; RETURN}; dad _ [0, 0, fixed, tame]; FOR i: INT IN [0..frame.seqSize) DO -- Normalize sons to x sequences for computations GetSize[frame.seq[i]]; son _ IF frame.xory=y THEN FlipSize[frame.seq[i].shell.size] ELSE frame.seq[i].shell.size; CheckXSeqForExpansionError[dad, son, frame.seq[i]]; dad.xfree _ MAX[dad.xfree, son.xfree]; -- fixed, tame, wild dad.x _ dad.x + son.x; dad.yfree _ IF MIN[dad.yfree,son.yfree]=fixed THEN fixed ELSE MAX[dad.yfree,son.yfree]; dad.y _ MAX[dad.y, son.y]; ENDLOOP; FOR i: INT IN [0..frame.seqSize) DO son _ IF frame.xory=y THEN FlipSize[frame.seq[i].shell.size] ELSE frame.seq[i].shell.size; IF dad.yfree=fixed AND son.yfree=wild THEN { log.PutF["\n WARNING: Limited wild %g width%g\n", IO.rope[ IF frame.xory=x THEN "Y" ELSE "X" ], IO.rope[ ListFrame[frame, 2] ] ]; EXIT}; ENDLOOP; frame.shell.size _ IF frame.xory=y THEN FlipSize[dad] ELSE dad}; CheckXSeqForExpansionError: PROC[size1, size2: Size, frame: Frame] = { IF (size1.y > size2.y AND size2.yfree=fixed) OR (size2.y > size1.y AND size1.yfree=fixed) THEN { log.PutF["\n ERROR: Size of %g not expandable", IO.rope[frame.shell.name]]; log.PutRope[ListFrame[frame.father, 2]]; log.Flush[]; Signal[]} }; PutSize: PUBLIC PROC[frame: Frame] = { dad, son: Size; freedom: Freedom; oneVariable: BOOL; cnt: ARRAY Freedom OF INT _ ALL[0]; length, diff: INT _ 0; IF frame.seqSize = 0 THEN RETURN; dad _ IF frame.xory=y THEN FlipSize[frame.shell.size] ELSE frame.shell.size; -- norm FOR ii: INT IN [0..frame.seqSize) DO son _ frame.seq[ii].shell.size; son _ IF frame.xory=y THEN FlipSize[son] ELSE son; -- norm CheckXSeqForExpansionError[dad, son, frame.seq[ii]]; length _ length + son.x; cnt[son.xfree] _ cnt[son.xfree] + 1; SELECT dad.yfree FROM wild => IF son.yfree=fixed THEN Signal[]; -- how can this happen? tame => IF son.yfree#tame THEN Signal[]; -- how can this happen? ENDCASE; IF (dad.yfree >= son.yfree) AND (dad.y=son.y) THEN LOOP; log.PutF["\n %g width changed from %6g %6g", IO.rope [IF frame.xory=x THEN "Y" ELSE "X"], IO.int[son.y], IO.rope[FreeRope[son.yfree]] ]; son.yfree _ MIN[dad.yfree, son.yfree]; son.y _ MAX[dad.y, son.y]; log.PutF[" to %6g %6g in: %g", IO.int[son.y], IO.rope[FreeRope[son.yfree]], IO.rope [frame[ii].shell.name] ]; frame.seq[ii].shell.size _ IF frame.xory=y THEN FlipSize[son] ELSE son; -- denorm ENDLOOP; diff _ dad.x - length; FOR freedom DECREASING IN Freedom DO IF cnt[freedom]>0 THEN EXIT ENDLOOP; oneVariable _ (cnt[tame]=1 AND cnt[wild]=0) OR (cnt[tame]=0 AND cnt[wild]=1); IF diff<0 THEN Signal[]; IF diff>0 OR diff=0 AND dad.xfree = fixed AND oneVariable THEN { SELECT dad.xfree FROM wild, tame => IF freedom#dad.xfree THEN Signal[]; ENDCASE; FOR ii: INT IN [0..frame.seqSize) WHILE cnt[freedom] > 0 DO incr: INT _ diff/cnt[freedom]; son _ frame.seq[ii].shell.size; son _ IF frame.xory=y THEN FlipSize[son] ELSE son; -- norm; IF son.xfree#freedom THEN LOOP; log.PutF["\n %g length changed from %6g %6g", IO.rope[IF frame.xory=x THEN "X" ELSE "Y"], IO.int[son.x], IO.rope[FreeRope[son.xfree]] ]; IF oneVariable THEN son.xfree _ dad.xfree; son.x _ son.x + incr; log.PutF[" to %6g %6g in: %g", IO.int[son.x], IO.rope[FreeRope[son.xfree]], IO.rope [frame[ii].shell.name] ]; diff _ diff - incr; cnt[freedom] _ cnt[freedom] - 1; frame.seq[ii].shell.size _ IF frame.xory=y THEN FlipSize[son] ELSE son; -- denorm ENDLOOP; IF diff#0 THEN ERROR}; FOR i: INT IN [0..frame.seqSize) DO PutSize[frame.seq[i]] ENDLOOP }; Signal: SIGNAL = CODE; PutPos: PUBLIC PROC[frame: Frame, new: CD.Position] = { cng: CD.Position _ [new.x-frame.shell.pos.x, new.y-frame.shell.pos.y]; pos: CD.Position _ frame.shell.pos _ new; IF frame.seqSize=0 THEN { FOR side: Side IN Side DO IF frame.shell.pins[side]=NIL THEN LOOP ELSE FOR pin: INT IN [0..frame.shell.pins[side].seqSize) DO frame.shell.pins[side][pin].pos.x _ frame.shell.pins[side][pin].pos.x + cng.x; frame.shell.pins[side][pin].pos.y _ frame.shell.pins[side][pin].pos.y + cng.y; ENDLOOP ENDLOOP; RETURN}; FOR i: INT IN [0..frame.seqSize) DO PutPos[frame.seq[i], pos]; SELECT frame.xory FROM x => pos.x _ pos.x + frame.seq[i].shell.size.x; y => pos.y _ pos.y + frame.seq[i].shell.size.y; ENDCASE ENDLOOP }; GetPins: PUBLIC PROC[frame: Frame] = { Merge: PROC[pins1, pins2: REF PinSeq] RETURNS[pins: REF PinSeq] = { pins _ NEW[PinSeq[pins1.seqSize+(IF pins2=NIL THEN 0 ELSE pins2.seqSize)]]; pins.locInfo _ MIN[pins1.locInfo, (IF pins2=NIL THEN unk ELSE pins2.locInfo)]; FOR i:INT IN [0..pins1.seqSize) DO pins[i ] _ pins1[i] ENDLOOP; IF pins2=NIL THEN RETURN[pins]; FOR i:INT IN [0..pins2.seqSize) DO pins[i+pins1.seqSize ] _ pins2[i] ENDLOOP }; pins: ARRAY Side OF REF PinSeq; IF frame.seqSize = 0 THEN RETURN; FOR side: Side IN Side DO pins[side] _ NEW[PinSeq[0]]; pins[side].locInfo _ fixed ENDLOOP; FOR i: INT IN [0..frame.seqSize) DO GetPins[frame.seq[i]]; SELECT frame.xory FROM x => { pins[top] _ Merge[pins[top], frame.seq[i].shell.pins[top]]; pins[bottom] _ Merge[pins[bottom], frame.seq[i].shell.pins[bottom]]}; y => { pins[right] _ Merge[pins[right], frame.seq[i].shell.pins[right]]; pins[left] _ Merge[pins[left], frame.seq[i].shell.pins[left]]}; ENDCASE; ENDLOOP; SELECT frame.xory FROM x => { pins[right] _ Merge[pins[right], frame.seq[frame.seqSize-1 ].shell.pins[right]]; pins[left] _ Merge[pins[left], frame.seq[0 ].shell.pins[left]]}; y => { pins[top] _ Merge[pins[top], frame.seq[frame.seqSize-1 ].shell.pins[top]]; pins[bottom] _ Merge[pins[bottom], frame.seq[0 ].shell.pins[bottom]]}; ENDCASE; frame.shell.pins _ pins}; FixOneSize: PUBLIC PROC [frame: Frame] RETURNS[fixed1: BOOL _ FALSE] = { FixOneSizeRecursive: PUBLIC PROC [fframe: Frame] RETURNS[ffixed1: BOOL _ FALSE] = { lastTame: INT _ -1; wildOrMultTamesFound: BOOL _ FALSE; FOR kid: INT IN [0..fframe.seqSize) DO SELECT (IF fframe.xory=x THEN fframe[kid].shell.size.xfree ELSE fframe[kid].shell.size.yfree) FROM fixed => LOOP; wild => wildOrMultTamesFound _ TRUE; ENDCASE => {IF lastTame#-1 THEN wildOrMultTamesFound _ TRUE; lastTame_kid}; ENDLOOP; IF lastTame#-1 AND wildOrMultTamesFound THEN { IF fframe.xory=x THEN {fframe[lastTame].shell.size.xfree _ fixed; log.PutRope["\n X length"]} ELSE {fframe[lastTame].shell.size.yfree _ fixed; log.PutRope["\n Y length"]}; log.PutF[" FIXED in %g", IO.rope[fframe[lastTame].shell.name]]; PutSize[fframe]; RETURN[TRUE]}; FOR kid: INT IN [0..fframe.seqSize) WHILE NOT ffixed1 DO ffixed1 _ FixOneSizeRecursive[fframe[kid]] ENDLOOP}; IF FixOneSizeRecursive[frame] THEN RETURN[TRUE]; IF frame.shell.size.xfree=tame THEN {frame.shell.size.xfree_fixed; PutSize[frame]; RETURN[TRUE]}; IF frame.shell.size.yfree=tame THEN {frame.shell.size.yfree_fixed; PutSize[frame]; RETURN[TRUE]}; RETURN[FALSE]}; TellKidsAboutDad: PUBLIC PROC [dad: Frame] = { FOR kid: INT IN [0..dad.seqSize) DO dad[kid].father _ dad; TellKidsAboutDad[dad[kid]] ENDLOOP}; Neighbor: PUBLIC PROC [leaf: Frame, side: Side] RETURNS[neighbor: Frame, ok: BOOL] = { NeighborCheck: PROC[frame: Frame] RETURNS[type: {eq, ok, out}] = { negh: CD.Rect _ CDBasics.RectAt[frame.shell.pos, [frame.shell.size.x,frame.shell.size.y]]; SELECT neighborSide FROM right => { IF seg.x2=negh.x2 AND seg.y1=negh.y1 AND seg.y2=negh.y2 THEN RETURN[eq]; IF seg.x2 NOT IN (negh.x1 .. negh.x2] THEN RETURN[out]}; left => { IF seg.x1=negh.x1 AND seg.y1=negh.y1 AND seg.y2=negh.y2 THEN RETURN[eq]; IF seg.x1 NOT IN [negh.x1 .. negh.x2) THEN RETURN[out]}; top => { IF seg.y2=negh.y2 AND seg.x1=negh.x1 AND seg.x2=negh.x2 THEN RETURN[eq]; IF seg.y2 NOT IN (negh.y1 .. negh.y2] THEN RETURN[out]}; bottom => { IF seg.y1=negh.y1 AND seg.x1=negh.x1 AND seg.x2=negh.x2 THEN RETURN[eq]; IF seg.y1 NOT IN [negh.y1 .. negh.y2) THEN RETURN[out]}; ENDCASE; SELECT neighborSide FROM right, left => { IF seg.y1 NOT IN [negh.y1 .. negh.y2) THEN RETURN[out]; IF seg.y2 NOT IN (negh.y1 .. negh.y2] THEN RETURN[out]; RETURN[ok]}; top, bottom => { IF seg.x1 NOT IN [negh.x1 .. negh.x2) THEN RETURN[out]; IF seg.x2 NOT IN (negh.x1 .. negh.x2] THEN RETURN[out]; RETURN[ok]}; ENDCASE }; neighborSide: Side _ OppSide[side]; seg: CD.Rect _ CDBasics.RectAt[leaf.shell.pos, [leaf.shell.size.x,leaf.shell.size.y]]; SELECT side FROM top => seg.y1 _ seg.y2; bottom => seg.y2 _ seg.y1; right => seg.x1 _ seg.x2; left => seg.x2 _ seg.x1; ENDCASE; FOR neighbor _ leaf.father, neighbor.father WHILE neighbor#NIL DO SELECT NeighborCheck[neighbor] FROM ok => EXIT; out => LOOP; ENDCASE => ERROR REPEAT FINISHED => { log.PutF["\n ERROR: %g side neighbor of %g is external to frame", IO.rope[SideRope[side]], IO.rope[leaf.shell.name]]; RETURN[NIL, FALSE]} ENDLOOP; DO IF neighbor.seqSize=0 THEN RETURN[neighbor, FALSE]; FOR i: INT IN [0..neighbor.seqSize) DO SELECT NeighborCheck[neighbor[i]] FROM out => LOOP; eq => {neighbor _ neighbor[i]; GOTO Found}; ENDCASE => {neighbor _ neighbor[i]; EXIT}; REPEAT Found=> EXIT; FINISHED => { log.PutF["\n ERROR: %g side neighbor of %g can't be identified", IO.rope[SideRope[side]], IO.rope[leaf.shell.name]]; RETURN[NIL, FALSE]} ENDLOOP; ENDLOOP; RETURN[neighbor, TRUE]}; FreeRope: ARRAY Freedom OF IO.ROPE _ ["fixed", "tame", "wild"]; ListFrame: PUBLIC PROC[frame: Frame, limit: INT _ -1] RETURNS[listing: IO.ROPE] = { out: IO.STREAM _ IO.ROS[]; LogFrame[frame, limit, out]; listing _ IO.RopeFromROS[out]}; LogFrame: PUBLIC PROC[frame: Frame, limit: INT _ -1, out: IO.STREAM _ NIL] = { Gauge: PROC[fframe: Frame, depth: INT] = { requiredOffset _ MAX[requiredOffset, depth+fframe.shell.name.Length[]]; FOR i: INT IN [0..fframe.seqSize) DO Gauge[fframe.seq[i], depth+1] ENDLOOP}; ListF: PROC[fframe: Frame, depth: INT] = { name: IO.ROPE _ name_fframe.shell.name; size: Size _ fframe.shell.size; pos: CD.Position _ fframe.shell.pos; IF depth=limit THEN RETURN; out.PutRope["\n"]; FOR i: INT IN [0..depth) DO out.PutRope[" "] ENDLOOP; out.PutRope[name]; THROUGH [name.Length[]+depth..requiredOffset) DO out.PutRope[" "] ENDLOOP; out.PutF[" %8g%8g", IO.int[size.x], IO.int[size.y] ]; out.PutF[" %8g%8g", IO.rope[FreeRope[size.xfree]], IO.rope[FreeRope[size.yfree]] ]; out.PutF[" %8g%8g", IO.int[pos.x], IO.int[pos.y] ]; IF fframe.seqSize#0 THEN IF fframe.xory=x THEN out.PutRope[" x seq"] ELSE out.PutRope[" y seq"]; IF fframe.unordered THEN out.PutRope[" ~"]; FOR i: INT DECREASING IN [0..fframe.seqSize) DO ListF[fframe.seq[i], depth+1] ENDLOOP}; requiredOffset: INT _ 0; IF out=NIL THEN out _ GetLog[]; Gauge[frame,0]; ListF[frame, 0]}; FullFrameName: PUBLIC PROC[frame: Frame] RETURNS[name: IO.ROPE] = { FOR temp: Frame _ frame.father, temp.father WHILE temp#NIL DO name _ Rope.Cat[temp.shell.name, ".", name] ENDLOOP; name _ name.Cat[frame.shell.name]}; FlattenOnce: PUBLIC PROC[frame: Frame] RETURNS[new: Frame] = {new _ TestMergeNodes[frame]}; TestMergeNodes: PUBLIC PROC[frame: Frame, testProc: TestMergeProc _ NIL] RETURNS[new: Frame] ~ { nlist: LIST OF REF; elist: LIST OF Frame; xory: XorY _ y; count: CARDINAL; FOR index: CARDINAL IN [0..frame.seqSize) DO IF testProc=NIL OR testProc[frame[index]] THEN { IF xory#frame[index].xory THEN ERROR; FOR element: CARDINAL IN [0..frame[index].seqSize) DO elist _ CONS[frame[index][element], elist] ENDLOOP} ELSE { IF elist#NIL THEN nlist _ CONS[elist, nlist]; elist _ NIL; nlist _ CONS[frame[index], nlist]}; REPEAT FINISHED => IF elist#NIL THEN nlist _ CONS[elist, nlist] ENDLOOP; count _ 0; FOR tlist: LIST OF REF _ nlist, tlist.rest WHILE tlist#NIL DO count _ count+1 ENDLOOP; new _ NewFrame[count, frame.xory, frame.shell.name, frame.data, frame.unordered]; FOR node: CARDINAL DECREASING IN [0..new.seqSize) DO WITH nlist.first SELECT FROM list: LIST OF Frame => { cnt: CARDINAL _ 0; FOR tlist: LIST OF Frame _ list, tlist.rest WHILE tlist#NIL DO cnt _ cnt+1 ENDLOOP; new[node] _ NewFrame[cnt, xory, "Connections", , list.first.unordered]; FOR element: CARDINAL DECREASING IN [0..new[node].seqSize) DO new[node][element] _ list.first; list _ list.rest ENDLOOP}; plaFrame: Frame => {new[node] _ plaFrame}; ENDCASE => ERROR; nlist _ nlist.rest ENDLOOP}; EnumFrameTopFirst: PUBLIC PROC[frame: Frame, proc: EnumProc] = { proc[frame]; FOR field: INT IN [0..frame.seqSize) DO EnumFrameTopFirst[frame[field], proc] ENDLOOP }; EnumFrameBotFirst: PUBLIC PROC[frame: Frame, proc: EnumProc] = { FOR field: INT IN [0..frame.seqSize) DO EnumFrameBotFirst[frame[field], proc] ENDLOOP; proc[frame] }; EnumFrameBotOnly: PUBLIC PROC[frame: Frame, proc: EnumProc] = { IF frame.seqSize=0 THEN proc[frame] ELSE FOR field: INT IN [0..frame.seqSize) DO EnumFrameBotOnly[frame[field],proc] ENDLOOP}; Key: TYPE = REF INT; ROPE: TYPE = IO.ROPE; WriteFrameShellFile: PROC [comm: CDSequencer.Command] = { inst: CD.Instance _ CDCommandOps.TheInstance[comm: comm, text: "Shell to File "]; IF inst#NIL THEN { log.PutRope[CDOps.Info[inst.ob]]; IF ~CDCells.IsCell[inst.ob] THEN log.PutRope[" is not a cell\n"] ELSE { shell: REF ShellRec; shellFile: REF ROPE _ NEW[ROPE _ comm.design.name.Cat[".shell"]]; IF comm.data#NIL THEN shellFile _ NARROW[comm.data] ELSE { log.PutRope["\n"]; shellFile _ NEW[ROPE _ TerminalIO.RequestRope["File name for shell: "]]}; shell _ ShellFromObject[inst.ob]; ShellToFile[shell] } } }; WriteFrameShellFileCT: Commander.CommandProc = { shell: REF ShellRec; file: ROPE _ CommandTool.NextArgument[cmd]; IF file=NIL THEN RETURN; shell _ ShellFromDesign[file]; ShellToFile[shell]}; ShellFromDesign: PUBLIC PROC[design: REF] RETURNS [shell: REF ShellRec] = { IF design#NIL AND ISTYPE[design, IO.ROPE] THEN design _ CDIO.ReadDesign[NARROW[design]]; shell _ ShellFromObject[ObjectFromDesign[NARROW[design]]]}; ObjectFromDesign: PROC[design: CD.Design] RETURNS [cell: CD.Object] = { multiple: BOOL; inst: CD.Instance; CDSimpleOps.Select[design, [0,0]]; [inst, multiple] _ CDOps.SelectedInstance[design]; IF multiple THEN ERROR; IF inst=NIL THEN log.PutRope["\n Shell from design . . . no cell at [0, 0]\n"]; IF inst#NIL THEN { log.PutF["\nShell from cell: %g", IO.rope[CDOps.Info[inst.ob]]]; IF ~CDCells.IsCell[inst.ob] THEN log.PutRope[" is not a cell\n"] ELSE RETURN[inst.ob] } }; ShellFromObject: PUBLIC PROC[cell: CD.Object] RETURNS [shell: REF ShellRec] = { DuplicatePinError: BOOL_FALSE; AddPinEntry: PWPins.InstanceEnumerator = { data: REF PinRec _ NEW[PinRec _ [ name: CDPinObjects.GetName[inst], side: PWPins.GetSide[cell, inst].side, size: inst.ob.size, pos: inst.location, layer: CDPinObjects.GetLayer[inst] ] ]; olddata: RedBlackTree.Node _ RedBlackTree.LookupNode[tables[data.side], GetKey[data]]; IF olddata#NIL THEN { oldPin: REF PinRec _ NARROW[olddata.data]; IF NOT DuplicatePinError OR NOT (Rope.Equal[oldPin.name, "VDD"] OR Rope.Equal[oldPin.name, "GND"]) OR NOT (Rope.Equal[oldPin.name, data.name]) THEN log.PutF[ "\n\n Duplicate Pin ERRORs:%g%g\n", IO.rope[ PinRope[ oldPin, [0,0] ] ], IO.rope[PinRope[data, [0,0]] ] ]; DuplicatePinError _ TRUE; RETURN}; RedBlackTree.Insert[tables[data.side], data, GetKey[data]]; cnt[data.side] _ cnt[data.side]+1}; SeqTable: PROC [userdata: RedBlackTree.UserData] RETURNS [stop: BOOL _ FALSE] = { data: REF PinRec _ NARROW[userdata]; shell.pins[data.side][index] _ data; index _ index+1}; tables: ARRAY Side OF RedBlackTree.Table; cnt: ARRAY Side OF INT _ ALL[0]; index: INT; FOR currentSide: Side IN Side DO tables[currentSide] _ RedBlackTree.Create[getKey: GetKey, compare: Compare] ENDLOOP; [] _ PWPins.EnumerateEdgePins[cell, AddPinEntry]; shell _ NEW[ShellRec _ [ ]]; shell.name _ CDDirectory.Name[cell]; shell.size _ FixedSize[CD.InterestSize[cell]]; FOR currentSide: Side IN Side DO shell.pins[currentSide] _ NEW[PinSeq[cnt[currentSide]]]; index _ 0; RedBlackTree.EnumerateIncreasing[tables[currentSide], SeqTable] ENDLOOP }; SideRope: PUBLIC ARRAY Side OF ROPE _ ["BOTTOM", "RIGHT", "TOP", "LEFT"]; ShellFromFile: PUBLIC PROC [shellName: ROPE] RETURNS [shell: REF ShellRec] = { tbp: IO.BreakProc = {RETURN[SELECT char FROM IN [IO.NUL .. IO.SP], ',, ':, '; => sepr, '[, '], '(, '), '{, '}, '", '+, '-, '*, '/, '@, '_ => break, ENDCASE => other]}; shellFile: ROPE _ shellName.Cat[".shell"]; in: IO.STREAM; cnt: ARRAY Side OF INT _ ALL[0]; pins: ARRAY Side OF LIST OF REF PinRec _ ALL[NIL]; shell _ NEW[ShellRec _ [name: shellName]]; in _ FS.StreamOpen[shellFile ! FS.Error => {in_NIL; CONTINUE}]; IF in=NIL THEN RETURN[shell]; shell.name _ IO.GetTokenRope[in].token; [ ] _ IO.GetTime[in]; shell.size.x _ IO.GetInt[in]; shell.size.y _ IO.GetInt[in]; shell.size.xfree _ fixed; shell.size.yfree _ fixed; DO name: ROPE _ IO.GetTokenRope[in, tbp ! IO.EndOfStream => EXIT].token; sideR: ROPE _ IO.GetTokenRope[in].token; posX: INT _ IO.GetInt[in]; posY: INT _ IO.GetInt[in]; sizeX: INT _ IO.GetInt[in]; sizeY: INT _ IO.GetInt[in]; layer: CD.Layer _ IO.GetInt[in]; data: REF PinRec _ NEW[PinRec _ [ name: name, side: bottom, pos: [posX, posY], size: [sizeX, sizeY], layer: LOOPHOLE[layer] ] ]; FOR test: Side IN Side DO IF Rope.Equal[sideR, SideRope[test]] THEN {data.side _ test; EXIT}; REPEAT FINISHED => ERROR ENDLOOP; cnt[data.side] _ cnt[data.side] + 1; pins[data.side] _ CONS[data, pins[data.side] ] ENDLOOP; in.Close[]; FOR side: Side IN Side DO shell.pins[side] _ NEW[PinSeq[cnt[side]]]; FOR pin: INT DECREASING IN [0..shell.pins[side].seqSize) DO shell.pins[side][pin] _ pins[side].first; pins[side] _ pins[side].rest ENDLOOP ENDLOOP }; PinRope: PROC[pin: REF PinRec, base: CD.Position] RETURNS[rope: ROPE] = { out: IO.STREAM _ IO.ROS[]; out.PutF["\n%g %-6g", IO.rope[pin.name], IO.rope[SideRope[pin.side]]]; out.PutF["%6g%6g%6g%6g%6g", IO.int[pin.pos.x-base.x], IO.int[pin.pos.y-base.y], IO.int[pin.size.x], IO.int[pin.size.y], IO.int[pin.layer]]; RETURN[ IO.RopeFromROS[out] ]}; ShellToFile: PUBLIC PROC[shell: REF ShellRec] = { shellFile: ROPE _ shell.name.Cat[".shell"]; tabStop45LookF: ROPE = "45 sp tabStops look.f"; node: TextNode.Ref; out: IO.STREAM _ FS.StreamOpen[shellFile, $create]; log.PutF["\n Writing pin file: %g . . . ", IO.rope[shellFile]]; out.PutF["%g %18g%6g%6g\n", IO.rope[shell.name], IO.time[], IO.int[shell.size.x], IO.int[shell.size.y]]; FOR side: Side IN Side DO FOR i: INT IN [0..shell.pins[side].seqSize) DO out.PutRope[ PinRope[shell.pins[side][i], shell.pos]] ENDLOOP ENDLOOP; out.PutRope["\n"]; out.Close[]; node _ PutGet.FromFile[shellFile]; NodeProps.PutProp[node.child, $Postfix, tabStop45LookF]; [ ] _ PutGet.ToFile[shellFile, node]; log.PutRope[" done\n"]}; NextSide: PUBLIC PROC [side: Side] RETURNS [next: Side] = {RETURN[SELECT side FROM bottom=>right, right=>top, top=>left, left=>bottom, ENDCASE=>ERROR]}; PrevSide: PUBLIC PROC [side: Side] RETURNS [prev: Side] = {RETURN[SELECT side FROM bottom=>left, left=>top, top=>right, right=>bottom, ENDCASE=>ERROR]}; OppSide: PUBLIC PROC [side: Side] RETURNS [opp: Side] = {RETURN[SELECT side FROM left=>right, right=>left, top=>bottom, bottom=>top, ENDCASE=>ERROR]}; GetSidePos: PUBLIC PROC [pin: REF PinRec] RETURNS [INT] = {RETURN[SELECT pin.side FROM left, right => pin.pos.y, ENDCASE => pin.pos.x]}; SetSidePos: PUBLIC PROC [pin: REF PinRec, pos: INT] = {SELECT pin.side FROM left, right => pin.pos.y_pos ENDCASE => pin.pos.x_pos}; REFToINT: PROC [ref: REF] RETURNS [INT] = {pin: REF PinRec _ NARROW[ref]; RETURN[GetSidePos[pin]*CD.layerNum + pin.layer]}; GetKey: PROC [userdata: RedBlackTree.UserData] RETURNS [RedBlackTree.Key] = {RETURN[userdata]}; Compare: PROC [k: RedBlackTree.Key, data: RedBlackTree.UserData] RETURNS [Basics.Comparison] = {RETURN[Basics.CompareINT[REFToINT[k], REFToINT[data]]]}; log: IO.STREAM _ NIL; GetLog: PUBLIC PROC RETURNS[IO.STREAM] = { logName: IO.ROPE _ "CDFrame.log"; IF log=NIL THEN { log _ ViewerIO.CreateViewerStreams[logName, NIL, logName].out; log.PutF["%g %g\n\n", IO.rope[logName], IO.time[]]}; RETURN[log]}; Commander.Register[proc: WriteFrameShellFileCT, key: "CDFrameShell"]; CDSequencer.ImplementCommand[a: $FrameShell, p: WriteFrameShellFile]; CDMenus.CreateEntry[$CellMenu, "Write frame shell file", $FrameShell]; [ ] _ GetLog[]; TerminalIO.WriteRope["FrameShell program loaded\n"]; END. <CDFrameImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Last Edited by Curry, January 27, 1986 8:28:59 am PST EXPORTS CDFrame SHARES CDSilTextCommands = CMos.cmos => CMos.met, textOb: CD.Object _ CDTexts.CreateText[pins[i].name, font, layer]; IF frame.orient#CDOrient.original THEN ERROR; IF frame.seqSize = 0 THEN { FOR side: Side IN Side DO bias: INT _ SELECT side FROM top, bottom => frame.shell.pos.x, ENDCASE => frame.shell.pos.y; IF frame.shell.pins[side]=NIL THEN LOOP ELSE IF frame.shell.pins[side].locInfo=fixed THEN FOR pin: INT IN [0..frame.shell.pins[side].seqSize) DO pos: INT _ GetSidePos[frame.shell.pins[side][pin]]; IF pos = unk THEN ERROR; SetSidePos[frame.shell.pins[side][pin], pos + bias]; ENDLOOP ENDLOOP; RETURN}; FixImpliedPins: PROC[frame: REF FrameRec] = { IF frame.seq # NIL THEN FOR i: INT IN [0..frame.seq.seqSize-1) DO { aSide: Side _ IF frame.seq.xory = x THEN right ELSE top; bSide: Side _ IF frame.seq.xory = x THEN left ELSE bottom; aPins: REF PinSeq _ frame.seq[i+0].shell.pins[aSide]; bPins: REF PinSeq _ frame.seq[i+1].shell.pins[bSide]; FOR aPin: INT IN [0..aPins.seqSize) DO IF aPins[aPin].pos#unk THEN LOOP; FOR bPin: INT IN [0..bPins.seqSize) DO IF ~Rope.Equal[bPins[bPin].name, aPins[aPin].name] THEN LOOP; IF bPins[bPin].pos=unk THEN ERROR; aPins[aPin].pos _ bPins[bPin].pos; IF aPins[aPin].size=unkSize THEN aPins[aPin].size _ bPins[bPin].size; EXIT REPEAT FINISHED => ERROR ENDLOOP; FOR bPin: INT IN [0..bPins.seqSize) DO IF bPins[bPin].pos#unk THEN LOOP; FOR aPin: INT IN [0..aPins.seqSize) DO IF ~Rope.Equal[aPins[aPin].name, bPins[bPin].name] THEN LOOP; IF aPins[aPin].pos=unk THEN ERROR; bPins[bPin].pos _ aPins[aPin].pos; IF bPins[bPin].size=unkSize THEN bPins[bPin].size _ aPins[aPin].size; EXIT REPEAT FINISHED => ERROR ENDLOOP; IF bPins.seqSize# aPins.seqSize THEN ERROR; SORT both ? Checkd that newly defined pins are still in range of cells FOR pin: INT IN [0..aPins.seqSize) DO IF ~Rope.Equal[aPins[pin].name, bPins[pin].name] THEN ERROR; IF aPins[pin].pos#bPins[pin].pos THEN ERROR ENDLOOP }; Shell Stuff Κ2ή˜šœ™Jšœ<™Jšœ˜—J˜šžœœœ˜Jšœ œœœ˜Jšœ#Οc˜@Jšœœ œ˜(Jšœ& ˜Jšœ.˜.Jšœœœ"œ˜Išœ œ˜&Jšœ˜Jšœ™Jšœ˜Jšœœ˜—Jšœ3˜3Jšœ3˜3Jšœ#˜#Jšœ3˜3šœœœ˜Jšœœœ˜-JšœœO˜W—Jšœœ*˜2Jšœœ7˜?Jšœœ*˜2Jšœœ1˜9Jšœ0˜2J™—šž œœœ œœœœ˜YJšœœ ˜šœ œœ ˜6Jšœ˜$—šœ œ˜Jšœœœ˜!Jšœœœœ˜@—Jšœ!˜!šœ œ˜Jšœœ˜$š œœœœœœ˜3JšœœC˜Kšœœ œ˜&Jšœ4˜4—Jšœ+˜+Jšœ-œ˜5—Jšœ˜—JšœB˜BJšœ.˜0Jšœœ1œ ˜EJ˜—šžœ˜Jš œ œœœœ ˜OJšœ œ˜šœ œ˜Jšœœ˜%Jšœœ˜šœœœ˜)Jšœ!˜!Jšœ!˜!Jšœœ˜—š œœœœœœ˜3Jšœœ ˜Jšœ>˜>JšœB™Bšœœ˜Jšœ(˜(Jšœ@˜@Jšœ)˜)Jšœ'˜'Jšœœ˜—šœœ˜Jšœ˜Jšœ˜Jšœ)˜)Jšœ>˜>Jšœœ˜—Jšœœ+˜3Jš˜—Jšœ˜ —J˜—šž œœœœœ œœ˜LJšœœœœD˜XJ™—šœ œ˜"Jšœ ˜ Jš œœœ œœ˜(šœ˜šœ˜šœœœ˜%Jšœ-œ˜5——šœ˜Jšœ œœ œ˜-šœ œ˜Jšœœ'œ ˜Ašœœ˜Jšœ˜Jšœ*œ˜1—šœ œœ˜Jšœœ˜Jšœœ˜ Jšœ4˜4šœ˜Jšœ5˜9Jšœ3˜7——š œœœ œ œœ ˜AJšœ˜Jšœœ ˜/—šœœœ˜Jšœœœœ˜(Jšœœ ˜/—šœœ˜Jšœœ˜$Jšœ˜Jšœ˜Jšœ˜Jšœ˜ —šœœ˜Jšœ0˜0Jšœœ˜*—šœ˜ Jšœ0˜0Jšœœ˜*——Jšœ0˜0Jšœ˜Jšœœœ ˜=—Jšœ˜ ——J˜šžœœœœ˜Cšœœœ˜6Jšœ/˜/Jšœ˜Jšœœ˜ —šœ˜Jšœœ˜šœ˜Jšœœ˜šœœœ˜'Jšœ.˜.Jšœœœœ˜2—Jšœœœ˜,Jšœ œ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ š œœ œœ˜2Jšœœœœ˜Jšœ˜Jšœœ˜"—Jšœ˜———J˜šœœ ˜LJšœœœ˜)šœ œœ$˜>Jšœœœ˜(—Jšœœ˜ Jšœ ˜ š œœœœœ˜4Jšœ>œ˜G——J˜šœœ ˜MJšœœœ˜)šœ œœ$˜>Jšœœœ˜0—Jšœœ˜ Jšœ ˜ š œœœœœ˜4Jšœ?œ˜H——J˜š ž œœœœœœ˜RJšœœ ˜š œœ œœœ œ˜UJšœœœ˜ —šœ˜Jšœœ.˜9šœ˜Jšœœ˜š œœ œœ˜.Jšœœ,œ˜?—šœ ˜Jšœœ˜&Jšœœ˜'—Jšœ1˜3———J˜šžœœ˜Jšœœœœ˜Kšžœœ˜Jšœ œœ˜(šœœœ˜%JšœV˜VJšœ˜ ——Jšœ œœœ˜-Jšœ-™-Jšœ6˜6Jšœ!˜!šœœ˜Jšœœœ˜(Jšœ œœœ˜šœ œ˜šœœ˜Jšœ˜ šœœ˜JšœJ˜JJšœI˜IJšœJ˜JJšœL˜LJšœK˜KJšœL˜LJšœL˜LJšœL˜LJšœœ˜—šœœ˜JšœE˜EJšœE˜EJšœE˜EJšœG˜GJšœG˜GJšœG˜GJšœG˜GJšœG˜GJšœœ˜—šœ œ˜šœ œœ˜$Jšœ œ-˜@Jšœ œœ˜——šœ˜Jšœ˜Jšœ˜Jšœ˜šœ˜Jšœœœ˜$Jšœ'˜'Jšœ˜Jšœ/˜/Jšœœœ œ ˜9—Jšœ˜ ——šœœ ˜Jšœœ)˜2Jšœœ˜4Jšœ˜—Jšœœ˜—Jšœ˜—šœ˜Jšœ(˜(Jšœœœ ˜:Jšœ)œœ ˜HJšœ6˜6Jšœœœœ ˜6Jšœœœ ˜=Jšœ*œœ ˜IJšœ+œœœ ˜DJšœ˜—Jš œœœœ$œ˜P—J™š žœœœœ œœ ˜@Jšœœœ˜—J˜šžœœœ˜&Jšœ œœ˜Jšœ˜šœœ˜Jšœ œœ œ˜*šœ œ˜Jšœœ+œ˜Kšœœ˜Jšœ˜šœœœœ˜?Jšœ˜#Jšœ!˜%——Jšœœ˜—Jšœœœœ˜VJšœ˜—Jšœ˜š œœœœ Πbc.˜UJšœ˜Jšœœœ#œ˜ZJšœ3˜3Jšœ œ ˜;Jšœ˜Jš œ œœœœœ˜WJšœ œ˜Jšœ˜—šœœœ˜#Jšœœœ#œ˜Zšœœœ˜,šœ1˜1Jšœœœœ˜-Jšœ œ˜(——Jšœ˜—Jšœœœœ˜@—J™šžœœ&˜Fšœœ˜/šœœœ˜0Jšœ0œ˜KJšœ(˜(Jšœ ˜ Jšœ ˜ ———J˜šžœœœ˜&Jšœ˜Jšœ˜Jšœ œ˜Jš œœ œœœ˜#Jšœœ˜Jšœœœ˜!Jš œœœœ ’˜Tšœœœ˜$Jšœ˜Jš œœœœ  ’˜@Jš‘œ˜4Jšœ˜Jšœ$˜$šœ ˜Jšœ œœ  ˜BJšœ œœ  ˜AJšœ˜—JšœœœŸœ˜8šœ-˜-Jšœœœœ˜,Jšœ œ˜.—Jšœ œ˜&Jšœ œ˜šœ˜Jšœ œœ˜N—Jš œœœœ ’˜QJšœ˜—Jšœ˜Jšœ  œœ œœœœœ˜IJšœœœœ˜MJšœœ ˜š œœœœ œ˜@šœ ˜Jšœœœ ˜1Jšœ˜—š œœœœ˜;Jšœœ˜Jšœ˜Jš œœœœ  ’œ˜@JšœœŸœ˜šœ-˜-Jšœœœœ˜+Jšœ œ˜.—Jšœ œ˜*Jšœ˜šœ˜Jšœ œœ˜N—Jšœ˜Jšœ ˜ Jš œœœœ ’˜QJšœ˜Jšœœœ˜——Jš œœœœœ˜D—J™Jšœœœ˜J˜šžœœœœ˜7Jšœœ?˜FJšœœ"˜)šœœ˜šœ œ˜šœ˜Jšœ˜ š œœœœ%˜;JšœN˜NJšœN˜NJš˜——Jšœœ˜——šœœœ˜#Jšœ˜šœ ˜Jšœ/˜/Jšœ/˜/Jšœœ˜———J™šžœœœ˜&š žœœœ œœ ˜CJš œœœœœœ˜KJš œœœœœœ˜NJš œœœœœ˜CJšœœœœ˜Jš œœœœ#œ˜O—Jšœœœœ˜Jšœœœ˜!šœ™šœ™šœ™Jšœ!™!Jšœ™—šœ™Jšœ ™ šœ1™1šœ6™6Jšœ3™3Jšœ™Jšœ4™4Jšœ™———Jšœ™Jšœ™——šœ œ˜Jšœ œ(œ˜@—šœœœ˜#Jšœ˜šœ ˜˜Jšœ=˜=JšœE˜E—˜JšœA˜AJšœA˜A—Jšœ˜—Jšœ˜—šœ ˜˜JšœP˜PJšœE˜E—˜JšœL˜LJšœI˜I—Jšœ˜—Jšœ˜—J™š ž œœœœ œœ˜Hš Πbnœœœœ œœ˜SJšœœ˜Jšœœœ˜#šœœœ˜&šœœ˜Jšœ˜!šœ˜'Jšœ œ˜Jšœ œ˜%Jšœœ œœ˜K——Jšœ˜—šœ œœ˜.šœ˜JšœH˜LJšœI˜M—Jšœœ$˜?JšœŸœœ˜—š œœœœœ˜5Jšœ ‘œœ˜7——Jš œ‘œœœœ˜0šœ˜Jšœ0Ÿœœ˜B—šœ˜Jšœ0Ÿœœ˜B—Jšœœ˜—J˜šžœœœ˜.šœœœ˜ Jšœ3œ˜>——J˜šžœœœ˜/Jšœœ˜&šž œœœ˜BJšœœR˜Zšœ˜šœ ˜ Jš œœœœœ˜HJš œœœœœ˜8—šœ ˜ Jš œœœœœ˜HJš œœœœœ˜8—šœ ˜ Jš œœœœœ˜HJš œœœœœ˜8—šœ ˜ Jš œœœœœ˜HJš œœœœœ˜8—Jšœ˜—šœ˜šœ˜Jš œœœœœ˜7Jš œœœœœ˜7Jšœ˜ —šœ˜Jš œœœœœ˜7Jš œœœœœ˜7Jšœ˜ —Jšœ˜ ——Jšœ$˜$JšœœO˜Xšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜—šœ)œ œ˜Ašœ˜#Jšœœ˜ Jšœœ˜ šœœœœ˜%šœA˜AJšœœ˜4—Jšœœœœ˜———š˜Jšœœœ œ˜3šœœœ˜&šœ˜&Jšœœ˜ Jšœ!œ˜-Jšœœ˜*—šœ œœ˜"šœ@˜@Jšœœ˜4—Jšœœœœ˜——Jšœ˜—Jšœ œ˜—J™J™šœ-™-šœ™šœ0™0Jšœ8™8Jšœ:™:Jšœ5™5Jšœ5™5šœ&™&šœ!™!šœ&™&Jšœ=™=Jšœ"™"Jšœ"™"JšœE™EJšœ&™&———šœ&™&šœ!™!šœ&™&Jšœ=™=Jšœ"™"Jšœ"™"JšœE™EJšœ&™&———Jšœ+™+Jšœ ™ Jšœ;™;šœ%™%Jšœ<™——Jšœ*˜*Jšœœ˜—Jšœœ˜——J™šžœœœ"˜@Jšœ ˜ šœœœ˜$Jšœ'œ˜3——šžœœœ"˜@šœœœ˜$Jšœ'œ˜1—Jšœ˜—šžœœœ"˜?šœ˜Jšœ ˜šœœœœ˜)Jšœ%œ˜0———J˜J™Jšœ ™ J˜Jšœœœœ˜Jšœœœœ˜J˜šžœœ ˜9JšœœJ˜Ršœœœ˜Jšœ"˜"šœ˜Jšœ!˜%šœ˜Jšœœ ˜Jš œ œœœœ#˜Ašœ ˜Jšœ œ ˜"šœ˜Jšœ˜Jšœ œœ5˜I——Jšœ!˜!Jšœ˜———J˜—šœ0˜0Jšœœ ˜Jšœœ!˜+Jšœœœœ˜Jšœ˜Jšœ˜J˜—šžœœœ œ˜)šœ œ˜!š œœœœ œœ˜)Jšœ œ œ ˜.—Jšœ)œ ˜;——J˜š žœœ œ œœ ˜GJšœ œ˜Jšœœ ˜Jšœ"˜"Jšœ2˜2Jšœ œœ˜Jšœœœ?˜Ošœœœ˜Jšœ"œ˜Ašœ˜Jšœ!˜%Jšœœ˜———J™šžœœœœ˜-Jšœ œ˜!Jšœœœ˜šœ+˜+šœ œ œ ˜$Jšœ"˜"Jšœ'˜'Jšœ˜Jšœ˜Jšœ(˜(—JšœW˜Wšœ œœ˜Jšœœ œ˜*šœœ˜Jšœœ!œ ˜Išœœ%˜+šœ.˜2Jšœ#œ˜F———Jšœœ˜Jšœ˜—Jšœ;˜;Jšœ#˜#—š žœœ#œœœ˜QJšœœ œ ˜%Jšœ$˜$Jšœ˜—Jšœœœ˜)Jš œœœœœ˜ Jšœœ˜ šœœ˜ JšœLœ˜T—Jšœ1˜1Jšœœ˜Jšœ$˜$Jšœœ˜/šœœ˜ Jšœœ˜8Jšœ ˜ Jšœ@œ˜J——Icode˜Jš œ œœœœ&˜IJ˜š ž œœœ œœ œ˜Nšœœœœ˜,Jš œœœœœ˜/Jšœ<˜Jšœœœ ˜4—Jšœ˜ —J˜JšœE˜EJšœE˜EJšœF˜FJšœ˜Jšœ4˜4J˜Jšœ˜—J˜—…—8ΛR