AttributePadFrame: PWCore.AttributesProc = {
data: CoreClasses.RecordCellType ← NARROW [cellType.data];
minX, minY: INT ← LAST[INT];
maxX, maxY: INT ← FIRST[INT];
left, right, top, bottom: CellInstance ← NIL;
IF data.size#5 THEN ERROR; -- 4 sides and inner
FOR i:
NAT
IN [0..data.size)
DO
IF BBox[data[i]].x1<minX THEN {left ← data[i]; minX ← BBox[data[i]].x1};
IF BBox[data[i]].x2>maxX THEN {right ← data[i]; maxX ← BBox[data[i]].x2};
IF BBox[data[i]].y1<minY THEN {bottom ← data[i]; minY ← BBox[data[i]].y1};
IF BBox[data[i]].y2>maxY THEN {top ← data[i]; maxY ← BBox[data[i]].y2};
ENDLOOP;
CoreProperties.PutCellInstanceProp[left, $PadFrameSide, $Left];
CoreProperties.PutCellInstanceProp[bottom, $PadFrameSide, $Bottom];
CoreProperties.PutCellInstanceProp[right, $PadFrameSide, $Right];
CoreProperties.PutCellInstanceProp[top, $PadFrameSide, $Top];
};
LayoutPadFrame: PWCore.LayoutProc = {
data: CoreClasses.RecordCellType ← NARROW [cellType.data];
leftInst, rightInst, topInst, bottomInst, innerInst: CellInstance ← NIL;
leftOb, rightOb, topOb, bottomOb, innerOb: CD.Object ← NIL;
prop: REF ← CoreProperties.GetCellTypeProp[cellType, $VerticalMetal];
innerDX: INT ← GetCTPropInt[cellType, $innerDX, 0];
innerDY: INT ← GetCTPropInt[cellType, $innerDY, 0];
vertLayer:
ROPE ←
IF prop=
NIL
THEN "metal2"
ELSE
NARROW[prop];
-- default: metal2 is vertical (to conform to standard cells)
horizLayer: ROPE ← IF Rope.Equal[vertLayer, "metal2"] THEN "metal" ELSE "metal2";
outerChanWidth: INT ← GetCTPropInt[cellType, $outerWidth, 90];
powerCellWidth: INT ← GetCTPropInt[cellType, $powerWidth, 200];
hLayer: CD.Layer ← CDSimpleRules.GetLayer[technologyKey, horizLayer];
vLayer: CD.Layer ← CDSimpleRules.GetLayer[technologyKey, vertLayer];
params: Cabbage.PadRingParams ←
NEW [Cabbage.PadRingParamsRec ← [
horizLayer: horizLayer,
vertLayer: vertLayer,
technologyKey: technologyKey, -- $cmosB
outerBTChanWidth: outerChanWidth, -- enough for xxx tracks
outerLRChanWidth: outerChanWidth, -- enough for xxx tracks
powerBTCellWidth : powerCellWidth, -- xxx lambda power busses
powerLRCellWidth : powerCellWidth, -- xxx lambda power busses
opt: noIncompletes,
signalSinglePinNets: TRUE]];
nets: Connections.Table ← Connections.CreateForRopes[];
innerPos: CD.Position;
leftSize, rightSize, topSize, bottomSize: CD.Position;
ConnectionsFromList:
PROC [nets: Connections.Table, inst: CellInstance, side: CoreGeometry.Side, layer:
CD.Layer] ~ {
FOR l: CoreRoute.WirePins ← CoreRoute.FilteredInstanceLayoutPins[inst, side], l.rest
WHILE l#
NIL
DO
actual: Wire ← l.first.wire;
name: ROPE ← CoreRoute.LabelInternal[data.internal, actual];
net: Connections.Net ← Connections.Fetch[nets, name].net;
widthVal: REF ANY ← CoreProperties.GetWireProp[actual, wireWidthProp];
width: INT ← IF widthVal = NIL THEN 0 ELSE NARROW[widthVal, REF INT]^;
IF layer#l.first.layer THEN LOOP;
IF l.first.min>l.first.max THEN ERROR;
IF net=NIL THEN net ← NEW [Connections.NetRec ← [name: name, width: width]]; [] ← Connections.Store[nets, name, net];
net.segments ←
CONS [
NEW [Connections.SegmentRec ← [object: PWCore.Layout[inst.type], range: [l.first.min, l.first.max], side: SideToSide[side], layer: l.first.layer]],
net.segments];
ENDLOOP;
};
IF data.size#5 THEN ERROR; -- 4 sides and inner
FOR i:
NAT
IN [0..data.size)
DO
SELECT CoreProperties.GetCellInstanceProp[data[i], $PadFrameSide]
FROM
$Left => leftInst ← data[i];
$Right => rightInst ← data[i];
$Top => topInst ← data[i];
$Bottom => bottomInst ← data[i];
NIL => innerInst ← data[i];
ENDCASE => ERROR;
ENDLOOP;
IF leftInst=NIL OR rightInst=NIL OR topInst=NIL OR bottomInst=NIL OR innerInst=NIL THEN ERROR;
leftOb ← PWCore.Layout[leftInst.type];
rightOb ← PWCore.Layout[rightInst.type];
topOb ← PWCore.Layout[topInst.type];
bottomOb ← PWCore.Layout[bottomInst.type];
innerOb ← PWCore.Layout[innerInst.type];
leftSize ← CD.InterestSize[leftOb];
rightSize ← CD.InterestSize[rightOb];
topSize ← CD.InterestSize[topOb];
bottomSize ← CD.InterestSize[bottomOb];
IF NOT(bottomSize.x=topSize.x AND leftSize.y=rightSize.y) THEN ERROR;
-- warning: the new Cabbage changes layer from inner to pads, so pads on the left will use their pins in vertLayer!!!
ConnectionsFromList[nets, leftInst, right, vLayer];
ConnectionsFromList[nets, rightInst, left, vLayer];
ConnectionsFromList[nets, topInst, bottom, hLayer];
ConnectionsFromList[nets, bottomInst, top, hLayer];
ConnectionsFromList[nets, innerInst, right, hLayer];
ConnectionsFromList[nets, innerInst, left, hLayer];
ConnectionsFromList[nets, innerInst, bottom, vLayer];
ConnectionsFromList[nets, innerInst, top, vLayer];
-- Call Cabbage
innerPos ← CDBasics.AddPoints[
[innerDX*lambda, innerDY*lambda],
Cabbage.Center[innerOb, NIL, bottomOb, NIL, rightOb, NIL, topOb, NIL, leftOb, params]
];
CoreGeometry.PutTrans[PWCore.extractMode.decoration, innerInst, [innerPos]];
CoreGeometry.PutTrans[PWCore.extractMode.decoration, bottomInst, [[leftSize.x, 0]]];
CoreGeometry.PutTrans[PWCore.extractMode.decoration, rightInst, [[leftSize.x+bottomSize.x, bottomSize.y]]];
CoreGeometry.PutTrans[PWCore.extractMode.decoration, topInst, [[leftSize.x, bottomSize.y+leftSize.y]]];
CoreGeometry.PutTrans[PWCore.extractMode.decoration, leftInst, [[0, bottomSize.y]]];
obj ← Cabbage.PadLimitedRoute[
inner: innerOb,
bottom: bottomOb,
right: rightOb,
top: topOb,
left: leftOb,
bottomLeft: NIL, bottomRight: NIL, topRight: NIL, topLeft: NIL,
innerPos: innerPos,
connections: nets,
parms: params,
name: CoreOps.GetCellTypeName[cellType]
];
};