<> <> <> <> DIRECTORY CD, CDBasics, CDCells, CDOrient, CDProperties, Core, CoreClasses, CoreCreate, CoreOps, CoreProperties, HashTable, OnionCore, OnionCoreArc, PW, PWCore, PadFrame, Rope, Sinix, Sisyph; PadFrameImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDCells, CDProperties, CoreClasses, CoreCreate, CoreOps, CoreProperties, HashTable, OnionCore, PW, PWCore, Rope, Sisyph EXPORTS PadFrame = BEGIN OPEN CoreCreate, PadFrame; ROPE: TYPE = PW.ROPE; packagePinProp: PUBLIC ATOM _ $PinInPackage; padFrameParamsProp: PUBLIC ATOM _ $PadFrameParams; padDesign: PUBLIC CD.Design; padCx: Sisyph.Context; AtomToObjName: PROC [atom: ATOM] RETURNS [rope: ROPE] ~ { rope _ SELECT atom FROM $Vdd => "VddPad", $Gnd => "GndPad", $PadVdd => "PadVddPad", $PadGnd => "PadGndPad", $In => "InputPad", $Out => "OutputPad", $Clk => "ClockPad", $IOTst => "IOTstPad", $Corner => "CornerPad", $Filler => "FillerPad", ENDCASE => ERROR; RETURN[Rope.Cat[rope, ".sch"]]; }; PadExtract: PROC [name: ROPE] RETURNS [cellType: Core.CellType] ~ { cellType _ Sisyph.ExtractSchematicByName[name: name, cx: padCx]; 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 => Instance[type: ct], -- all bindings are implicit ENDCASE => Instance[type: ct, pa1: ["Pad", pad], pa2: pa1, pa3: pa2, pa4: pa3, pa5: pa4]; CoreProperties.PutCellInstanceProp[inst, packagePinProp, NEW[NAT _ pos]]; newInsts _ CONS[inst, iL]; }; <<-- posL should have same length as pad.size>> AddPads: PUBLIC PROC [iL: CellInstances, pad: Wire, type: ATOM, posL: LIST OF NAT, pa1, pa2, pa3, pa4: PA _ []] RETURNS [newInsts: CellInstances] ~ { i: NAT _ 0; FOR positionL: LIST OF NAT _ posL, positionL.rest WHILE positionL#NIL DO newInsts _ AddPad[iL, pad[i], type, positionL.first, pa1, pa2, pa3, pa4]; i_i+1; ENDLOOP; }; Segment: PUBLIC PROC [first, size: NAT] RETURNS [list: LIST OF NAT _ NIL] ~ { FOR i: NAT IN [0..size) DO list _ CONS[first+i, list]; ENDLOOP; }; LayoutDontFlatten: PROC [cellType: CellType] RETURNS [obj: CD.Object] = { obj _ PWCore.Layout[cellType]; CDProperties.PutObjectProp[obj, $DontFlatten, $DontFlatten]; }; PadData: TYPE = RECORD [ instance: CoreClasses.CellInstance _ NIL, pos: CD.Position _ [0, 0], rot: CD.Orientation _ CDOrient.original ]; AllPadsData: TYPE = RECORD [c: SEQUENCE nbOfPads: NAT OF PadData]; PadFrame: PUBLIC PWCore.LayoutProc = { IsCorner: PROC [i: NAT] RETURNS [BOOL_FALSE] ~ { RETURN[i=0 OR i=ny OR i=ny+nx OR i=2*ny+nx]; }; rotT: CD.Orientation = CDOrient.original; rotL: CD.Orientation = CDOrient.rotate90; rotB: CD.Orientation = CDOrient.rotate180; rotR: CD.Orientation = CDOrient.rotate270; pos: CD.Position; -- current pad origin data: CoreClasses.RecordCellType _ NARROW [cellType.data]; inner: CoreClasses.CellInstance _ NIL; nets: HashTable.Table _ HashTable.Create[]; <<-- measure one pad>> cornerPad: CD.Object _ PWCore.Layout[PadExtract[AtomToObjName[$Corner]]]; fillerPad: CD.Object _ PWCore.Layout[PadExtract[AtomToObjName[$Filler]]]; padSize: CD.Position _ CD.InterestSize[fillerPad]; params: PadFrameParameters _ NARROW[CoreProperties.GetCellTypeProp[cellType, padFrameParamsProp]]; 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]]; outerSize: CD.Position _ [(nx-1)*dx, (ny-1)*dx]; innerSize: CD.Position; <<>> <<-- 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 inner#NIL => ERROR; refNat=NIL => inner _ 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 _ rotT; -- 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 _ rotL; -- 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 _ rotB; -- 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 _ rotR; -- 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; <<-- Start with an empty cell>> obj _ PW.CreateEmptyCell[]; <<-- Position the inner>> innerSize _ CD.InterestSize[PWCore.Layout[inner.type]]; IF params.innerPos=[0, 0] THEN { params.innerPos _ CDBasics.SubPoints[outerSize, innerSize]; params.innerPos _ [params.innerPos.x/2, params.innerPos.y/2]; }; [] _ PW.IncludeInCell[obj, LayoutDontFlatten[inner.type], params.innerPos]; <<-- Include all the pads in obj>> FOR i: NAT IN [0 .. nbOfPads) DO [] _ PW.IncludeInCell[ obj, IF allPads[i].instance=NIL THEN IF IsCorner[i] THEN cornerPad ELSE fillerPad ELSE LayoutDontFlatten[allPads[i].instance.type], allPads[i].pos, allPads[i].rot ]; ENDLOOP; <<-- Create the nets for the inner>> BEGIN EachInnerWirePin: PWCore.EachWirePinProc ~ { actual: Wire _ CoreClasses.CorrespondingActual[inner, wire]; name: ROPE _ CoreOps.GetFullWireName[data.internal, actual]; net: OnionCore.Net _ NARROW [HashTable.Fetch[nets, actual].value]; IF layer#params.radialLayer THEN RETURN; IF net=NIL THEN {net _ NEW [OnionCore.NetRec _ [name: name]]; [] _ HashTable.Store[nets, actual, net]}; IF min>max THEN ERROR; min _ min+(IF side=left OR side=right THEN params.innerPos.y ELSE params.innerPos.x); max _ max+(IF side=left OR side=right THEN params.innerPos.y ELSE params.innerPos.x); IF min>max THEN ERROR; IF side=top OR side=left THEN {w: INT _ min; min _ max; max _ w}; net.innerSegs _ CONS [ NEW [OnionCoreArc.SegRec _ [min, max, side, side]], net.innerSegs]; }; [] _ PWCore.EnumerateWirePins[inner.type, EachInnerWirePin]; END; <<-- Create the nets for the pads>> FOR i: NAT IN [0 .. nbOfPads) DO EachPadWirePin: PWCore.EachWirePinProc ~ { actual: Wire _ CoreClasses.CorrespondingActual[allPads[i].instance, wire]; name: ROPE _ CoreOps.GetFullWireName[data.internal, actual]; net: OnionCore.Net _ NARROW [HashTable.Fetch[nets, actual].value]; pos: CD.Position _ allPads[i].pos; innerSide: PWCore.Side; pt1, pt2: INT; IF layer#params.radialLayer THEN RETURN; IF side#bottom THEN RETURN; IF net=NIL THEN {net _ NEW [OnionCore.NetRec _ [name: name]]; [] _ HashTable.Store[nets, actual, net]}; IF min>max THEN ERROR; SELECT allPads[i].rot FROM rotT => {pt1 _ min+pos.x; pt2 _ max+pos.x; innerSide _ top}; rotB => {pt1 _ pos.x+dx-max; pt2 _ pos.x+dx-min; innerSide _ bottom}; rotL => {pt1 _ pos.y+min; pt2 _ pos.y+max; innerSide _ left}; rotR => {pt1 _ pos.y+dx-max; pt2 _ pos.y+dx-min; innerSide _ right}; ENDCASE => ERROR; IF pt1>pt2 THEN ERROR; IF innerSide=top OR innerSide=left THEN {w: INT _ pt1; pt1 _ pt2; pt2 _ w}; net.outerSegs _ CONS [ NEW [OnionCoreArc.SegRec _ [pt1, pt2, innerSide, innerSide]], net.outerSegs]; }; IF allPads[i].instance#NIL THEN [] _ PWCore.EnumerateWirePins[allPads[i].instance.type, EachPadWirePin]; ENDLOOP; PW.SetInterestRect[obj, outerSize]; <<-- Call Onion>> IF NOT OnionCore.IncludeInOuter[obj, nets, params.innerPos, innerSize, outerSize, params.radialLayer, params.ringLayer] THEN ERROR; PW.RepositionCell[obj]; obj _ PW.Flatten[obj]; }; DecoratePadFrame: PWCore.DecorateProc = { <> }; Init: PROC ~ { defaultGlobalNames: LIST OF ROPE _ CONS["PadGnd", CONS["PadVdd", Sisyph.defaultGlobalNames]]; IF padDesign=NIL THEN { -- not yet read padDesign _ PW.OpenDesign["Pads"]; padCx _ Sisyph.Create[design: padDesign, globalNames: defaultGlobalNames]; }; }; <<>> [] _ PWCore.RegisterLayoutAtom[$PadFrame, PadFrame, DecoratePadFrame]; Init[]; <<>> END. <<>>