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