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];
};