<> <> <> <> <> <> DIRECTORY Cabbage, CD, CDBasics, CDInstances, CDOps, CDSimpleRules, CedarProcess, Connections, Convert, Core, CoreClasses, CoreCreate, CoreOps, CoreProperties, CoreGeometry, PW, PWCore, EUPadFrame, Rope, RTBasic, Sisyph; EUPadFrameImpl: CEDAR PROGRAM IMPORTS Cabbage, CD, CDBasics, CDInstances, CDOps, CDSimpleRules, CedarProcess, Connections, Convert, CoreClasses, CoreCreate, CoreOps, CoreProperties, CoreGeometry, PW, PWCore, Rope, Sisyph EXPORTS EUPadFrame = BEGIN OPEN EUPadFrame; <> Signal: PUBLIC SIGNAL [message: ROPE] = CODE; padFrameParamsProp: PUBLIC ATOM _ $EUPadFrameParams; PadExtract: PROC [parameters: PadFrameParameters, name: ATOM] RETURNS [cellType: Core.CellType] ~ { cellType _ Sisyph.ES[ name: Rope.Cat[Convert.RopeFromAtom[name, FALSE], "Pad.sch"], cx: Sisyph.Create[design: GetDesign[parameters]] ]; IF CoreProperties.GetCellTypeProp[cellType, $Layout]=NIL THEN ERROR; }; GetDesign: PROC [parameters: PadFrameParameters] RETURNS [design: CD.Design] = { design _ parameters.design; IF design#NIL THEN RETURN; design _ PW.OpenDesign[IF parameters.library=NIL THEN "CommonPads" ELSE parameters.library]; IF design=NIL THEN SIGNAL Signal["Cannot find library"]; parameters.design _ design; }; <> AddPad: PUBLIC PROC [pads: Pads, public: WR, type: ATOM, pos: NAT, pa1, pa2, pa3, pa4: PA _ []] RETURNS [Pads] ~ { pas: LIST OF PA _ NIL; IF pa4#[] THEN pas _ CONS [pa4, pas]; IF pa3#[] THEN pas _ CONS [pa3, pas]; IF pa2#[] THEN pas _ CONS [pa2, pas]; IF pa1#[] THEN pas _ CONS [pa1, pas]; RETURN [CONS [[public: public, type: type, pos: pos, pas: pas], pads]]; }; AddPadList: PUBLIC PROC [pads: Pads, public: WR, type: ATOM, pos: NAT, pas: LIST OF PA _ NIL] RETURNS [Pads] ~ { RETURN [CONS [[public: public, type: type, pos: pos, pas: pas], pads]]; }; AddPads: PUBLIC PROC [pads: Pads, public: Wire, type: ATOM, firstPos: NAT, reverse: BOOL _ FALSE, pa1, pa2, pa3, pa4: PA _ []] RETURNS [news: Pads] ~ { news _ pads; FOR i: NAT IN [firstPos .. firstPos + public.size) DO news _ AddPad[news, public[IF reverse THEN public.size-1-i ELSE i], type, i, pa1, pa2, pa3, pa4]; ENDLOOP; }; CreatePadFrame: PUBLIC PROC [public: WireSeq, onlyInternal: WireSeq, innerInstance: CellInstance, pads: Pads, params: PadFrameParametersRec, name: ROPE _ NIL, props: Core.Properties _ NIL] RETURNS [fullChip: CellType] = { parameters: PadFrameParameters _ NEW [PadFrameParametersRec _ params]; instances: CoreCreate.CellInstances _ NIL; nx: NAT _ parameters.nbPadsX; ny: NAT _ parameters.nbPadsY; nbOfPads: NAT _ nx + ny + nx + ny; fillerPad: CellType _ PadExtract[parameters, $Filler]; cornerPad: CellType _ PadExtract[parameters, $Corner]; padsData: REF PadsData _ NEW [PadsData[nbOfPads]]; <> WHILE pads#NIL DO pad: Pad = pads.first; inst: CellInstance _ NIL; SELECT pad.type FROM $Filler, $Corner => SIGNAL Signal["Caller not supposed fill those pads! Read interface comments!"]; $Vdd, $Gnd, $PadVdd, $PadGnd, $Logo, $Copyright, $Name => inst _ CoreCreate.Instance[PadExtract[parameters, pad.type]]; -- all bindings are implicit $Analog, $In, $Out, $Clk, $IOTst, $Tristate => -- remove this! inst _ CoreCreate.InstanceList[ PadExtract[parameters, pad.type], CONS [["Pad", pad.public], pad.pas] ]; ENDCASE => inst _ CoreCreate.InstanceList[ PadExtract[parameters, pad.type], CONS [["Pad", pad.public], pad.pas] ]; < SIGNAL Signal["Unknown type of pad"];>> IF padsData[pad.pos].instance#NIL THEN SIGNAL Signal["Two pads at the same position"]; padsData[pad.pos].instance _ inst; pads _ pads.rest; ENDLOOP; <> FOR i: NAT IN [0 .. nbOfPads) DO IF padsData[i].instance=NIL THEN padsData[i].instance _ CoreCreate.Instance[ IF i=0 OR i=ny OR i=ny+nx OR i=2*ny+nx THEN cornerPad ELSE fillerPad ]; instances _ CONS [padsData[i].instance, instances]; ENDLOOP; <> BEGIN <<-- measure one pad>> padSize: CD.Position _ CD.InterestSize[PWCore.Layout[fillerPad]]; dx: INT _ padSize.x; dy: INT _ padSize.y; trans: CD.Transformation; -- current pad origin <<-- Left>> trans _ [[-dy, dx*(ny-1)], rotate90]; -- ul FOR i: NAT IN [0 .. ny) DO padsData[i].trans _ trans; trans.off.y _ trans.off.y-dx; ENDLOOP; <<-- Bottom>> trans _ [[-dy, -dy], rotate180]; padsData[ny].trans _ trans; -- ll trans.off.x _ 0; FOR i: NAT IN [ny+1 .. ny+nx) DO padsData[i].trans _ trans; trans.off.x _ trans.off.x+dx; ENDLOOP; <<-- Right>> trans _ [[(nx-1)*dx, -dy], rotate270]; padsData[ny+nx].trans _ trans; -- lr trans.off.y _ trans.off.y+dy; FOR i: NAT IN [ny+nx+1 .. ny+nx+ny) DO padsData[i].trans _ trans; trans.off.y _ trans.off.y+dx; ENDLOOP; <<-- Top>> trans _ [[(nx-1)*dx, dx*(ny-1)], original]; -- ur FOR i: NAT IN [2*ny+nx .. 2*ny+nx+nx) DO padsData[i].trans _ trans; trans.off.x _ trans.off.x-dx; ENDLOOP; END; instances _ CONS [innerInstance, instances]; -- innerInstance is the first instance (this detail is used in the LayoutProc) parameters.padsData _ padsData; fullChip _ CoreCreate.Cell[public: public, onlyInternal: onlyInternal, instances: instances, name: name, props: props]; PWCore.SetLayout[fullChip, $EUPadFrame, padFrameParamsProp, parameters]; }; <> SideToSide: PROC [side: CoreGeometry.Side] RETURNS [RTBasic.Side] = { RETURN [SELECT side FROM top => top, bottom => bottom, left => left, right => right, ENDCASE => ERROR ]; }; IsRoutable: PROC [parameters: PadFrameParameters, side: CoreGeometry.Side, layer: CD.Layer] RETURNS [BOOL] = { RETURN [layer=CDSimpleRules.GetLayer[GetDesign[parameters].technology, (IF side=top OR side=bottom THEN parameters.vertLayer ELSE parameters.horizLayer)]]; }; AddConnection: PROC [nets: Connections.Table, internal: WireSeq, actual: Wire, object: CD.Object, min, max: INT, side: CoreGeometry.Side, layer: CD.Layer] = { name: ROPE _ CoreOps.GetFullWireNames[internal, actual].first; net: Connections.Net _ Connections.Fetch[nets, name].net; IF net=NIL THEN { net _ NEW [Connections.NetRec _ [name: name]]; [] _ Connections.Store[nets, name, net]; }; net.segments _ CONS [ NEW [Connections.SegmentRec _ [object: object, range: [min, max], side: SideToSide[side], layer: layer]], net.segments]; }; Abut: PROC [parameters: PadFrameParameters, start, end: NAT] RETURNS [obj: CD.Object] = { instances: CD.InstanceList _ NIL; FOR i: NAT IN [start .. end) DO padData: PadData = parameters.padsData[i]; pad: CD.Object = PWCore.Layout[padData.instance.type]; off: CD.Position = CDBasics.SubPoints[padData.trans.off, CDBasics.BaseOfRect[CDBasics.MapRect[CD.InterestRect[pad], [[0, 0], padData.trans.orient]]]]; instances _ CONS [CDInstances.NewInst[pad, [off, padData.trans.orient]], instances]; ENDLOOP; obj _ PW.CreateCell[instances]; }; Rotate: PROC [padData: PadData] RETURNS [obj: CD.Object] = { obj _ PW.CreateRotation[PWCore.Layout[padData.instance.type], padData.trans.orient]; }; <> LayoutPadFrame: PWCore.LayoutProc = { parameters: PadFrameParameters _ NARROW [CoreProperties.GetCellTypeProp[cellType, padFrameParamsProp]]; padsData: REF PadsData _ parameters.padsData; data: CoreClasses.RecordCellType _ NARROW [cellType.data]; innerInstance: CellInstance _ data[0]; inner, bottomLeft, bottom, bottomRight, right, topRight, top, topLeft, left: CD.Object; nets: Connections.Table _ Connections.CreateForRopes[]; params: Cabbage.PadRingParams _ NEW [Cabbage.PadRingParamsRec _ [ horizLayer: parameters.horizLayer, vertLayer: parameters.vertLayer, outerBTChanWidth: parameters.outerChanWidth, outerLRChanWidth: parameters.outerChanWidth, powerBTCellWidth: parameters.powerCellWidth, powerLRCellWidth: parameters.powerCellWidth, opt: noIncompletes, signalSinglePinNets: TRUE ]]; dx: INT _ CD.InterestSize[PWCore.Layout[PadExtract[parameters, $Filler]]].x; dy: INT _ CD.InterestSize[PWCore.Layout[PadExtract[parameters, $Filler]]].y; nx: NAT _ parameters.nbPadsX; ny: NAT _ parameters.nbPadsY; priority: CedarProcess.Priority _ CedarProcess.GetPriority[]; innerPos: CD.Position; <<-- Adds the nets for the inner>> EachInnerWirePin: CoreGeometry.EachWirePinProc ~ { actual: Wire _ CoreClasses.CorrespondingActual[innerInstance, wire]; name: ROPE _ CoreOps.GetFullWireName[data.internal, actual]; IF NOT IsRoutable[parameters, side, layer] THEN RETURN; IF Rope.Equal[name, "PadVdd"] OR Rope.Equal[name, "PadGnd"] THEN ERROR; IF min>max THEN ERROR; AddConnection[nets, data.internal, actual, inner, min, max, side, layer]; }; <<>> <<-- Create the objects to pass to the router>> inner _ PWCore.Layout[innerInstance.type]; bottomLeft _ Rotate[padsData[ny]]; bottom _ Abut[parameters, ny+1, ny+nx]; bottomRight _ Rotate[padsData[ny+nx]]; right _ Abut[parameters, ny+nx+1, ny+nx+ny]; topRight _ Rotate[padsData[2*ny+nx]]; top _ Abut[parameters, 2*ny+nx+1, 2*ny+nx+nx]; topLeft _ Rotate[padsData[0]]; left _ Abut[parameters, 1, ny]; <<-- Create the nets for the inner>> [] _ PWCore.Layout[innerInstance.type]; -- to make sure the cellType is decorated [] _ CoreGeometry.EnumerateNonOverlappingSides[PWCore.extractMode.decoration, innerInstance.type, EachInnerWirePin]; <<-- Create the nets for the pads>> FOR i: NAT IN [0 .. padsData.nbOfPads) DO EachPadWirePin: CoreGeometry.EachWirePinProc ~ { actual: Wire _ CoreClasses.CorrespondingActual[padsData[i].instance, wire]; pos: CD.Position _ padsData[i].trans.off; pt1, pt2: INT; object: CD.Object; name: ROPE _ CoreOps.GetFullWireName[data.internal, actual]; IF side#bottom THEN RETURN; IF Rope.Equal[name, "PadVdd"] OR Rope.Equal[name, "PadGnd"] THEN ERROR; IF min>max THEN ERROR; SELECT padsData[i].trans.orient FROM original => {pt1 _ min+pos.x; pt2 _ max+pos.x; side _ bottom; object _ top}; rotate180 => {pt1 _ pos.x+dx-max; pt2 _ pos.x+dx-min; side _ top; object _ bottom}; rotate90 => {pt1 _ pos.y+min; pt2 _ pos.y+max; side _ right; object _ left}; rotate270 => {pt1 _ pos.y+dx-max; pt2 _ pos.y+dx-min; side _ left; object _ right}; ENDCASE => ERROR; IF NOT IsRoutable[parameters, side, layer] THEN RETURN; IF pt1>pt2 THEN ERROR; AddConnection[nets, data.internal, actual, object, pt1, pt2, side, layer]; }; [] _ PWCore.Layout[padsData[i].instance.type]; -- to make sure the cellType is decorated IF i#0 AND i#ny AND i#ny+nx AND i#2*ny+nx THEN [] _ CoreGeometry.EnumerateNonOverlappingSides[PWCore.extractMode.decoration, padsData[i].instance.type, EachPadWirePin]; ENDLOOP; <<-- Call Cabbage>> innerPos _ CDBasics.AddPoints[parameters.centerDisplacement, Cabbage.Center[inner, bottomLeft, bottom, bottomRight, right, topRight, top, topLeft, left, params]]; CoreGeometry.PutTrans[PWCore.extractMode.decoration, innerInstance, [[innerPos.x+dy, innerPos.y+dy]]]; CedarProcess.CheckAbort[]; CedarProcess.SetPriority[background]; obj _ Cabbage.PadLimitedRoute[inner, bottomLeft, bottom, bottomRight, right, topRight, top, topLeft, left, innerPos, nets, params, CoreOps.GetCellTypeName[cellType]]; CedarProcess.SetPriority[priority]; }; <> DecoratePadframe: PWCore.DecorateProc = { parameters: PadFrameParameters _ NARROW [CoreProperties.GetCellTypeProp[cellType, padFrameParamsProp]]; padsData: REF PadsData _ parameters.padsData; dy: INT _ CD.InterestSize[PWCore.Layout[PadExtract[parameters, $Filler]]].y; FOR i: NAT IN [0 .. padsData.nbOfPads) DO trans: CoreGeometry.Transformation _ CDOps.FitObjectI[ob: PWCore.Layout[padsData[i].instance.type], location: padsData[i].trans.off, orientation: padsData[i].trans.orient]; trans.off _ [trans.off.x+dy, trans.off.y+dy]; CoreGeometry.PutTrans[PWCore.extractMode.decoration, padsData[i].instance, trans]; ENDLOOP; CoreGeometry.PutRecordLazyPins[PWCore.extractMode.decoration, cellType, CD.InterestRect[obj]]; }; <> [] _ PWCore.RegisterLayoutAtom[$EUPadFrame, LayoutPadFrame, DecoratePadframe]; <<>> END. <<>>