DIRECTORY CD, CDBasics, CDCells, CDCreateLabels, CDProperties, CDSymbolicObjects, CMosB, ImagerFont, PGA144, PW, PWDescr, PWPins, Rope; PGA144Impl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDCells, CDCreateLabels, CDProperties, CDSymbolicObjects, CMosB, ImagerFont, PW, PWDescr, PWPins, Rope EXPORTS PGA144 = BEGIN OPEN PGA144; ROPE: TYPE = PW.ROPE; PadFrame: TYPE = ARRAY[1..144] OF PW.Object; Side: TYPE = PWPins.Side; MakeOuter: PUBLIC PROC [obj: PW.Object, renameProc: PWPins.RenameProc] RETURNS [cell: PW.Object] = BEGIN height: INT _ CD.InterestSize[IOTristatePad].y- 3 * CMosB.lambda; -- sniff, sniff: hack!!! CDCells.SetInterestRect[obj, CDBasics.Extend[CD.InterestRect[obj], -height]]; cell _ PWPins.RenamePins[obj, renameProc]; END; MakePadFrame: PUBLIC PROC [padDescr: PWDescr.Descriptor, innerSize: CD.Position _ [0, 0], pack: BOOL _ FALSE] RETURNS [frame: PW.Object] = BEGIN pos: CD.Position; dx1, dx2, dy1, dy2: INT; pads: PadFrame; ThePad: PROC [atom: ATOM] RETURNS [obj: PW.Object] = BEGIN obj _ SELECT atom FROM $IOTst => IOTristatePad, $In => InputPad, $Out => OutputPad, $Clock => ClockPad, $Vdd => VddPad, $Gnd => GndPad, $PadVdd => PadVddPad, $PadGnd => PadGndPad, $Empty => EmptyPad, ENDCASE => NIL; END; font: ImagerFont.Font _ ImagerFont.Find["Xerox/TiogaFonts/Helvetica10B"]; PlaceEachItem: PWDescr.ForEachItemProc = BEGIN seq: PWDescr.PadRef _ NARROW[item.specificRef]; side: Side _ IndexToSide[seq[0]]; -- first pin of the item reverse: BOOL _ side=top OR side=left; FOR i: INT IN [0..seq.size) DO index: INT _ IF reverse THEN seq.size-i-1 ELSE i; compositeName: ROPE _ IF seq.size>1 THEN PWPins.Index[item.name, index] ELSE item.name; KeepPin: PWPins.InstanceEnumerator -- [inst: CD.Instance] RETURNS [quit: BOOL _ FALSE] -- = { oldRope: ROPE _ CDSymbolicObjects.GetName[inst]; newApp: CD.Instance; IF Rope.Equal[oldRope, "label"] THEN { name: ROPE _ compositeName; label: PW.Object; posx, posy: INT _ -1; WHILE posx<0 OR posy<0 DO label _ CDCreateLabels.CreateTextCell[NIL, compositeName, font, 2, CMosB.met]; posx _ (inst.ob.size.x - label.size.x)/2; posy _ (inst.ob.size.y - label.size.y)/2; name _ Rope.Substr[name, 0, Rope.Length[name]-1]; ENDLOOP; CDCells.SetInterestRect[label, [-posx, -posy, inst.ob.size.x-posx, inst.ob.size.y-posy]]; newApp _ NEW[CD.InstanceRep _ [ ob: label, location: [inst.location.x+posx, inst.location.y+posy], orientation: inst.orientation]]; } ELSE { newRope: ROPE _ SELECT TRUE FROM Rope.Equal[oldRope, "enableWrite"] => Rope.Concat[item.name, ".enableWrite"], Rope.Equal[oldRope, "dataOut"] => Rope.Concat[compositeName, ".dataOut"], Rope.Equal[oldRope, "dataIn"] => Rope.Concat[compositeName, ".dataIn"], Rope.Equal[oldRope, "data"] => compositeName, -- data ENDCASE => oldRope; -- anything else newApp _ NEW [CD.InstanceRep _ [ ob: CDSymbolicObjects.CreatePin[inst.ob.size], location: inst.location, orientation: inst.orientation, properties: CDProperties.DCopyProps[inst.properties]]]; CDSymbolicObjects.SetName[newApp, newRope]; }; cellPtr.contents _ CONS[newApp, cellPtr.contents]; }; cell: PW.Object _ PW.CreateEmptyCell[]; pad: PW.Object _ ThePad[NARROW[item.data, ATOM]]; cellPtr: CD.CellPtr; app: CD.Instance _ NEW[CD.InstanceRep _ [ob: pad]]; CDProperties.PutInstanceProp[app, $StopEnumerateDeepPins, $StopEnumerateDeepPins]; cellPtr _ NARROW[cell.specificRef]; cellPtr.contents _ CONS[app, cellPtr.contents]; [] _ PWPins.EnumerateDeepPins[pad, KeepPin]; CDCells.SetInterestRect[cell, CD.InterestRect[pad]]; PW.RepositionCell[cell]; IF pads[seq[i]]=NIL THEN pads[seq[i]] _ cell ELSE ERROR; -- no conflict please ENDLOOP; END; topPadRow, leftPadRow, botPadRow, rightPadRow: PW.Object; PW.WriteF["Generating the Pad Frame\n"]; InitPGA144[]; pads _ InitPadFrame[]; PWDescr.EnumerateItems[padDescr, PlaceEachItem]; IF pack THEN BEGIN innerSize.x _ MAX[ SideLength[pads, top].totalPadsLength, SideLength[pads, bottom].totalPadsLength]; innerSize.y _ MAX[ SideLength[pads, left].totalPadsLength, SideLength[pads, right].totalPadsLength]; END; topPadRow _ PWPins.RenamePins[PadFrameSide[pads, innerSize, top]]; leftPadRow _ PWPins.RenamePins[PW.Rot90[PadFrameSide[pads, innerSize, left]]]; botPadRow _ PWPins.RenamePins[PW.Rot180[PadFrameSide[pads, innerSize, bottom]]]; rightPadRow _ PWPins.RenamePins[PW.Rot270[PadFrameSide[pads, innerSize, right]]]; frame _ PW.CreateEmptyCell[]; pos _ CD.InterestSize[topPadRow]; dy1 _ CD.InterestSize[botPadRow].y; dy2 _ CD.InterestSize[rightPadRow].y; dx1 _ CD.InterestSize[leftPadRow].x; dx2 _ CD.InterestSize[botPadRow].x ; [] _ PW.IncludeInCell[frame, botPadRow, [0, 0]]; [] _ PW.IncludeInCell[frame, topPadRow, [dx1, dy2]]; [] _ PW.IncludeInCell[frame, leftPadRow, [0, dy1]]; [] _ PW.IncludeInCell[frame, rightPadRow, [dx2, 0]]; PW.RepositionCell[frame]; END; PadFrameSide: PROC [pads: PadFrame, innerSize: CD.Position, side: Side] RETURNS [padFrameSide: PW.Object] = BEGIN Filler: PROC [fillingWidth: INT] RETURNS [cell: PW.Object] = {cell _ PW.LeftFillerCell[IOTristatePad, fillingWidth]}; listOb: PW.ListOb _ NIL; fillingCell: PW.Object; totalPadsLength, toSpend, nbEmpty, fillingWidth, leftOver: INT _ 0; low, hi: INT; [low, hi] _ SideToInterval[side]; [totalPadsLength, nbEmpty] _ SideLength[pads, side]; toSpend _ (IF IsVertical[side] THEN innerSize.y ELSE innerSize.x) - totalPadsLength; IF toSpend<0 THEN ERROR; -- proposed inner size is too small IF nbEmpty#0 AND toSpend#0 THEN fillingWidth _ toSpend/nbEmpty; leftOver _ toSpend-fillingWidth*nbEmpty; -- the remainder, for the corner IF nbEmpty=0 OR fillingWidth=0 THEN fillingCell _ NIL ELSE fillingCell _ Filler[fillingWidth]; listOb _ LIST[pads[low]]; IF leftOver#0 THEN listOb _ CONS[Filler[leftOver], listOb]; FOR i: INT IN (low..hi] DO IF pads[i]#NIL THEN listOb _ CONS[pads[i], listOb] ELSE IF fillingCell#NIL THEN listOb _ CONS[fillingCell, listOb]; ENDLOOP; padFrameSide _ PW.AbutListX[listOb]; END; SideToInterval: PROC [side: Side] RETURNS [low, hi: INT] = BEGIN SELECT side FROM left => {low _ 1; hi _ 36}; bottom => {low _ 37; hi _ 72}; right => {low _ 73; hi _ 108}; top => {low _ 109; hi _ 144}; ENDCASE => ERROR; END; IndexToSide: PROC [index: INT] RETURNS [side: Side] = BEGIN side _ SELECT index FROM <37 => left, <73 => bottom, <109 => right, <145 => top, ENDCASE => ERROR; END; IsVertical: PROC[side: Side] RETURNS [BOOL] = {RETURN[side=left OR side=right]}; SideLength: PROC [pads: PadFrame, side: Side] RETURNS [totalPadsLength, nbEmpty: INT _ 0] = BEGIN low, hi: INT; [low, hi] _ SideToInterval[side]; FOR i: INT IN [low+1..hi] DO -- we skip the corner IF pads[i]#NIL THEN totalPadsLength _ totalPadsLength+CD.InterestSize[pads[i]].x ELSE nbEmpty _ nbEmpty+1; ENDLOOP; END; InitPadFrame: PROC [] RETURNS [pads: PadFrame] = BEGIN pads[1] _ PW.Inst[GndCornerPad, LIST["1"], FALSE]; pads[73] _ PW.Inst[GndCornerPad, LIST["73"], FALSE]; pads[37] _ PW.Inst[VddCornerPad, LIST["37"], FALSE]; pads[109] _ PW.Inst[VddCornerPad, LIST["109"], FALSE]; pads[18] _ pads[54] _ pads[90] _ pads[126] _ PadGndPad; pads[19] _ pads[55] _ pads[91] _ pads[127] _ PadVddPad; END; Segment: PUBLIC PROC [first, howMany: INT] RETURNS [padRef: PWDescr.PadRef] = BEGIN OccupiedOnPGA144: PROC [index: INT] RETURNS [busy: BOOL] = {busy _ SELECT index FROM 1, 18, 19, 37, 54, 55, 73, 90, 91, 109, 126, 127 => TRUE, ENDCASE => FALSE;}; index: INT _ first; padRef _ NEW[PWDescr.PadRec[howMany]]; FOR i: INT IN [0..howMany) DO WHILE OccupiedOnPGA144[index] DO index _ index+1; ENDLOOP; -- search next free slot padRef[i] _ index; index _ index+1; ENDLOOP; END; Single: PUBLIC PROC [where: INT] RETURNS [padRef: PWDescr.PadRef] = {padRef _ Segment[where, 1];}; InputPad, OutputPad, IOTristatePad, VddPad, GndPad, PadVddPad, PadGndPad, ClockPad, EmptyPad: PW.Object; VddCornerPad, GndCornerPad: PW.Object; InitPGA144: PROC [] = BEGIN padsDesign: CD.Design _ PW.OpenDesign["CMosPadLibraryPGA144.dale"]; InputPad _ PW.Get[padsDesign, "InputPad"]; OutputPad _ PW.Get[padsDesign, "OutputPad"]; IOTristatePad _ PW.Get[padsDesign, "IOTristatePad"]; VddPad _ PW.Get[padsDesign, "VddPad"]; GndPad _ PW.Get[padsDesign, "GndPad"]; PadVddPad _ PW.Get[padsDesign, "PadVddPad"]; PadGndPad _ PW.Get[padsDesign, "PadGndPad"]; ClockPad _ PW.Get[padsDesign, "ClockPad"]; VddCornerPad _ PW.Get[padsDesign, "VddCornerPad"]; GndCornerPad _ PW.Get[padsDesign, "GndCornerPad"]; EmptyPad _ PW.Get[padsDesign, "EmptyPad"]; END; END. ฎPGA144Impl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Created by: Monier, May 3, 1985 3:28:40 pm PDT Last edited by: Monier, July 3, 1985 3:10:27 pm PDT Bertrand Serlet March 26, 1986 2:09:38 pm PST -- This generator produces a pad frame for the PGA144, and assigns the power pads automatically -- Assumptions: -- We can put at most 36 pins per side, 3 of them being already assigned -- If we number "1" the first pin on a side, going counter-clockwise (e.g. top pin on left side), then we have 1=(Gnd on left and right, Vdd on top and bottom), 18=PadGnd, and 19=PadVdd. -- The first pad (Vdd or Gnd) of a side is located in the corner -- Pads are on a 200 microns minimum pitch, except the power pads which are on a 400 microns pitch and are double-bonded. Corner pads are even wider. -- The pins expected on pads are the following: on IOTristatePad: dataOut, enableWrite, dataIn on OutputPad: dataOut, enableWrite on InputPad and ClockPad: data -- Pins will be renamed as follows (aasuming an item kBus) on IOTristatePad: kBus[1].dataOut, kBus.enableWrite, kBus[1].dataIn on OutputPad: kBus[1].dataOut, kBus.enableWrite on InputPad and ClockPad: kBus[1] -- If an item (say kBus) comprises more than one pad, PGA144 will do a renaming of the pins and generate labels as kBus[0].dataIn, kBus[1].dataIn, . . . The index grows with the coordinate, i.e. from left to right and from bottom to top. If the item is composed of only one pad, then no index is added to the name. -- Prepares a pad frame for routing by PWOnion -- Build the pad frame -- Every pin is renamed: "data" -> "Signal[12]", "enableWrite" -> "Signal.enableWrite", and the other pins are just pushed up without renaming. -- Place pads in slots, if they are free, and they should be -- Create a new pad frame and initialize it, i.e. place the power pins -- Place the pads in their slot -- If packing is required, compute the size of the pad frame -- Make the four sides -- Place them -- Build a side, of length size, made of the object pads[from] until pads[to]; -- The idea is to keep the bonding wires from angling too much, so the filling material is distributed proportionnally among the empty slots. If no slot is empty (i.e. 36 pads on the side), then the empty space is assigned to the corners. -- Every side owns one corner: counter-clockwise, a side puts its first pad in the corner. -- Figure out how much space is wasted, and find if there is an empty slot -- Make the filling cell -- Start with the corner and the extra space, if any -- Assemble: the list is reversed, but abut works left to right, and the orientation in the pad frame is counter-clockwise, so it is correct. -- Final assembly -- Dealing with the mapping pad->bonding pin -- the four corners get a power pad for the chip, with a number to help bonding -- the centers get a pair of power pads for pad drivers -- Standard pads -- Fetch the pads from the source design CornerPad _ PW.Get[padsDesign, "CornerPad"]; ส ˜– "Cedar" stylešœ™Jšœ ฯmœ1™