<> <> <> <> DIRECTORY Cabbage, CD, CDBasics, CDCells, CDInstances, CDOrient, CDSimpleRules, CedarProcess, Connections, Core, CoreClasses, CoreCreate, CoreOps, CoreProperties, CoreGeometry, PW, PWCore, PadFrame, Rope, RTBasic, Sisyph; PadFrameImpl: CEDAR PROGRAM IMPORTS Cabbage, CD, CDBasics, CDCells, CDInstances, CDSimpleRules, CedarProcess, Connections, CoreClasses, CoreCreate, CoreOps, CoreProperties, CoreGeometry, PW, PWCore, Rope, Sisyph EXPORTS PadFrame = BEGIN OPEN CoreCreate, PadFrame; packagePinProp: PUBLIC ATOM _ $PinInPackage; padFrameParamsProp: PUBLIC ATOM _ $PadFrameParams; padDesign: PUBLIC CD.Design _ PW.OpenDesign["Pads"]; padCx: Sisyph.Context _ Sisyph.Create[design: padDesign]; AtomToObjName: PROC [atom: ATOM] RETURNS [rope: ROPE] ~ { rope _ SELECT atom FROM $Vdd => "VddPad", $Gnd => "GndPad", $PadVdd => "PadVddPad", $PadGnd => "PadGndPad", $Analog => "AnalogPad", $In => "InputPad", $Out => "OutputPad", $Clk => "ClockPad", $IOTst => "IOTstPad", $Corner => "CornerPad", $Filler => "FillerPad", $Logo => "LogoPad", $Copyright => "CopyrightPad", $Name => "NamePad", ENDCASE => ERROR; RETURN [Rope.Cat[rope, ".sch"]]; }; PadExtract: PROC [name: ROPE] RETURNS [cellType: Core.CellType] ~ { cellType _ Sisyph.ExtractSchematicByName[name: name, cx: padCx]; IF CoreProperties.GetCellTypeProp[cellType, $Layout]=NIL THEN PWCore.SetGet[cellType, padDesign]; }; AddPad: PUBLIC PROC [iL: CellInstances, pad: WR, type: ATOM, pos: NAT, pa1, pa2, pa3, pa4: PA _ []] RETURNS [newInsts: CellInstances] ~ { ct: CellType _ PadExtract[AtomToObjName[type]]; inst: CellInstance _ SELECT type FROM $Vdd, $Gnd, $PadVdd, $PadGnd, $Logo, $Copyright, $Name => Instance[type: ct], -- all bindings are implicit ENDCASE => Instance[ct, ["Pad", pad], pa1, pa2, pa3, pa4]; CoreProperties.PutCellInstanceProp[inst, packagePinProp, NEW[NAT _ pos]]; newInsts _ CONS [inst, iL]; }; AddPads: PUBLIC PROC [iL: CellInstances, pad: Wire, type: ATOM, firstPos: NAT, reverse: BOOL _ FALSE, pa1, pa2, pa3, pa4: PA _ []] RETURNS [newInsts: CellInstances] ~ { FOR i: NAT IN [firstPos .. firstPos + pad.size) DO newInsts _ AddPad[iL, pad[IF reverse THEN pad.size-1-i ELSE i], type, i, pa1, pa2, pa3, pa4]; ENDLOOP; }; PadData: TYPE = RECORD [ instance: CoreClasses.CellInstance _ NIL, pos: CD.Position _ [0, 0], -- [0, 0] is the lower-left of the cavity rot: CD.Orientation _ CDOrient.original ]; AllPadsData: TYPE = RECORD [c: SEQUENCE nbOfPads: NAT OF PadData]; rotT: CD.Orientation = CDOrient.original; rotL: CD.Orientation = CDOrient.rotate90; rotB: CD.Orientation = CDOrient.rotate180; rotR: CD.Orientation = CDOrient.rotate270; fillerPad: CD.Object _ PWCore.Layout[PadExtract[AtomToObjName[$Filler]]]; cornerPad: CD.Object _ PWCore.Layout[PadExtract[AtomToObjName[$Corner]]]; <<-- measure one pad>> padSize: CD.Position _ CD.InterestSize[fillerPad]; Abut: PROC [allPads: REF AllPadsData, start, end: NAT] RETURNS [obj: CD.Object] = { obj _ PW.CreateEmptyCell[]; FOR i: NAT IN [start .. end) DO [] _ PW.IncludeInCell[ obj, IF allPads[i].instance=NIL THEN fillerPad ELSE PWCore.Layout[allPads[i].instance.type], allPads[i].pos, allPads[i].rot ]; ENDLOOP; PW.RepositionCell[obj]; }; Rotate: PROC [allPads: REF AllPadsData, start: NAT] RETURNS [obj: CD.Object] = { obj _ PW.ChangeOrientation[ IF allPads[start].instance=NIL THEN cornerPad ELSE PWCore.Layout[allPads[start].instance.type], allPads[start].rot]; }; PadFrame: PWCore.LayoutProc = { IsCorner: PROC [i: NAT] RETURNS [BOOL_FALSE] ~ { RETURN[i=0 OR i=ny OR i=ny+nx OR i=2*ny+nx]; }; inner, bottomLeft, bottom, bottomRight, right, topRight, top, topLeft, left: CD.Object; pos: CD.Position; -- current pad origin data: CoreClasses.RecordCellType _ NARROW [cellType.data]; innerInst: CoreClasses.CellInstance _ NIL; nets: Connections.Table _ Connections.CreateForRefs[]; params: PadFrameParameters _ NARROW [CoreProperties.GetCellTypeProp[cellType, padFrameParamsProp]]; parms: Cabbage.PadRingParams _ NEW [Cabbage.PadRingParamsRec _ [horizLayer: params.horizLayer, vertLayer: params.vertLayer, opt: noIncompletes, signalSinglePinNets: TRUE]]; nx: NAT _ params.nbPadsX; ny: NAT _ params.nbPadsY; dx: INT _ padSize.x; dy: INT _ padSize.y; nbOfPads: NAT _ nx + ny + nx + ny; allPads: REF AllPadsData _ NEW [AllPadsData[nbOfPads]]; priority: CedarProcess.Priority _ CedarProcess.GetPriority[]; <<>> <<-- fill allPads[i].instance and inner>> FOR i: NAT IN [0 .. data.size) DO refNat: REF NAT _ NARROW [CoreProperties.GetCellInstanceProp[data[i], packagePinProp]]; SELECT TRUE FROM refNat=NIL AND innerInst#NIL => ERROR; refNat=NIL => innerInst _ data[i]; allPads[refNat^].instance#NIL => ERROR; ENDCASE => allPads[refNat^].instance _ data[i]; ENDLOOP; <<-- Left>> pos _ [-dy, dx*(ny-1)]; IF allPads[0].instance#NIL THEN ERROR; allPads[0].pos _ pos; allPads[0].rot _ rotL; -- ul FOR i: NAT IN [1..ny) DO pos.y _ pos.y-dx; allPads[i].pos _ pos; allPads[i].rot _ rotL; ENDLOOP; <<-- Bottom>> pos _ [-dy, -dy]; IF allPads[ny].instance#NIL THEN ERROR; allPads[ny].pos _ pos; allPads[ny].rot _ rotB; -- ll pos.x _ 0; FOR i: NAT IN [ny+1 .. ny+nx) DO allPads[i].pos _ pos; allPads[i].rot _ rotB; pos.x _ pos.x+dx; ENDLOOP; <<-- Right>> pos _ [(nx-1)*dx, -dy]; IF allPads[ny+nx].instance#NIL THEN ERROR; allPads[ny+nx].pos _ pos; allPads[ny+nx].rot _ rotR; -- lr pos.y _ pos.y+dy; FOR i: NAT IN [ny+nx+1 .. ny+nx+ny) DO allPads[i].pos _ pos; allPads[i].rot _ rotR; pos.y _ pos.y+dx; ENDLOOP; <<-- Top>> pos _ [(nx-1)*dx, dx*(ny-1)]; IF allPads[2*ny+nx].instance#NIL THEN ERROR; allPads[2*ny+nx].pos _ pos; allPads[2*ny+nx].rot _ rotT; -- ur FOR i: NAT IN [2*ny+nx+1 .. 2*ny+nx+nx) DO pos.x _ pos.x-dx; allPads[i].pos _ pos; allPads[i].rot _ rotT; ENDLOOP; <<-- Create the objects to pass to the router>> inner _ PWCore.Layout[innerInst.type]; bottomLeft _ Rotate[allPads, ny]; bottom _ Abut[allPads, ny+1, ny+nx]; bottomRight _ Rotate[allPads, ny+nx]; right _ Abut[allPads, ny+nx+1, ny+nx+ny]; topRight _ Rotate[allPads, 2*ny+nx]; top _ Abut[allPads, 2*ny+nx+1, 2*ny+nx+nx]; topLeft _ Rotate[allPads, 0]; left _ Abut[allPads, 1, ny]; <<-- Create the nets for the inner>> BEGIN EachInnerWirePin: CoreGeometry.EachWirePinProc ~ { actual: Wire _ CoreClasses.CorrespondingActual[innerInst, wire]; name: ROPE _ CoreOps.GetFullWireNames[data.internal, actual].first; net: Connections.Net _ Connections.Fetch[nets, actual].net; innerSide: RTBasic.Side _ SELECT side FROM top => top, bottom => bottom, left => left, right => right, ENDCASE => ERROR; IF layer#CDSimpleRules.GetLayer[$cmosB, (IF side=top OR side=bottom THEN params.vertLayer ELSE params.horizLayer)] THEN RETURN; IF net=NIL THEN {net _ NEW [Connections.NetRec _ [name: name]]; [] _ Connections.Store[nets, actual, net]}; IF min>max THEN ERROR; net.segments _ CONS [ NEW [Connections.SegmentRec _ [object: inner, range: [min, max], side: innerSide, layer: layer]], net.segments]; }; [] _ PWCore.InterestRect[innerInst.type]; -- to make sure the cellType is decorated [] _ CoreGeometry.EnumerateNonOverlappingSides[PWCore.extractMode.decoration, innerInst.type, EachInnerWirePin]; END; <<-- Create the nets for the pads>> FOR i: NAT IN [0 .. nbOfPads) DO EachPadWirePin: CoreGeometry.EachWirePinProc ~ { actual: Wire _ CoreClasses.CorrespondingActual[allPads[i].instance, wire]; name: ROPE _ CoreOps.GetFullWireNames[data.internal, actual].first; net: Connections.Net _ Connections.Fetch[nets, actual].net; pos: CD.Position _ allPads[i].pos; innerSide: RTBasic.Side; pt1, pt2: INT; object: CD.Object; IF side#bottom THEN RETURN; IF net=NIL THEN {net _ NEW [Connections.NetRec _ [name: name]]; [] _ Connections.Store[nets, actual, net]}; IF min>max THEN ERROR; SELECT allPads[i].rot FROM rotT => {pt1 _ min+pos.x; pt2 _ max+pos.x; innerSide _ bottom; object _ top}; rotB => {pt1 _ pos.x+dx-max; pt2 _ pos.x+dx-min; innerSide _ top; object _ bottom}; rotL => {pt1 _ pos.y+min; pt2 _ pos.y+max; innerSide _ right; object _ left}; rotR => {pt1 _ pos.y+dx-max; pt2 _ pos.y+dx-min; innerSide _ left; object _ right}; ENDCASE => ERROR; IF layer#CDSimpleRules.GetLayer[$cmosB, (IF innerSide=top OR innerSide=bottom THEN params.vertLayer ELSE params.horizLayer)] THEN RETURN; IF pt1>pt2 THEN ERROR; net.segments _ CONS [ NEW [Connections.SegmentRec _ [object: object, range: [pt1, pt2], side: innerSide, layer: layer]], net.segments]; }; IF NOT IsCorner[i] AND allPads[i].instance#NIL THEN { [] _ PWCore.InterestRect[allPads[i].instance.type]; -- to make sure the cellType is decorated [] _ CoreGeometry.EnumerateNonOverlappingSides[PWCore.extractMode.decoration, allPads[i].instance.type, EachPadWirePin]; }; ENDLOOP; <<-- Call Cabbage>> CedarProcess.CheckAbort[]; CedarProcess.SetPriority[background]; obj _ Cabbage.PadLimitedRoute[inner, bottomLeft, bottom, bottomRight, right, topRight, top, topLeft, left, CDBasics.AddPoints[params.centerDisplacement, Cabbage.Center[inner, bottomLeft, bottom, bottomRight, right, topRight, top, topLeft, left, parms]], nets, parms, CoreOps.GetCellTypeName[cellType]]; <<-- we decorate the PadFrame>> BEGIN ir: CD.Rect _ CD.InterestRect[obj]; FOR i: NAT IN [0 .. nbOfPads) DO EachPair: CoreOps.EachWirePairProc = { pins: LIST OF CD.Instance _ NIL; -- previous pins of the public IF NOT CoreOps.RecursiveMember[cellType.public, actualWire] THEN RETURN; pins _ CoreGeometry.GetPins[PWCore.extractMode.decoration, actualWire]; CoreGeometry.PutTransfWireIRLazyPins[PWCore.extractMode.decoration, actualWire, publicWire, transf, ir]; WHILE pins#NIL DO CoreGeometry.PutPins[PWCore.extractMode.decoration, actualWire, CONS [pins.first, CoreGeometry.GetPins[PWCore.extractMode.decoration, actualWire]]]; pins _ pins.rest; ENDLOOP; }; transf: CD.Instance; IF IsCorner[i] OR allPads[i].instance=NIL THEN LOOP; transf _ CDInstances.NewInstI[ob: PWCore.Layout[allPads[i].instance.type], location: allPads[i].pos, orientation: allPads[i].rot]; CDInstances.Translate[transf, [dy, dy]]; -- modifies in place! [] _ CoreOps.VisitBinding[allPads[i].instance.actual, allPads[i].instance.type.public, EachPair]; ENDLOOP; CoreGeometry.PutIR[PWCore.extractMode.decoration, cellType, ir]; END; CedarProcess.SetPriority[priority]; }; NoDecorate: PWCore.DecorateProc = {}; [] _ PWCore.RegisterLayoutAtom[$PadFrame, PadFrame, NoDecorate]; <<>> END. <<>>