PadFrameImpl.mesa
Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved.
Louis Monier June 14, 1986 6:32:41 pm PDT
Bertrand Serlet February 23, 1987 3:31:42 am PST
Last edited by: Christian Jacobi, January 8, 1987 7:06:47 pm PST
DIRECTORY
Cabbage,
CD, CDBasics, CDInstances, CDOps, CDSimpleRules,
CedarProcess, Connections, Convert,
Core, CoreClasses, CoreCreate, CoreOps, CoreProperties,
CoreGeometry, PW, PWCore, PWObjects, PadFrame, Rope, RTBasic, Sisyph;
PadFrameImpl: CEDAR PROGRAM
IMPORTS Cabbage, CD, CDBasics, CDInstances, CDOps, CDSimpleRules, CedarProcess, Connections, Convert, CoreClasses, CoreCreate, CoreOps, CoreProperties, CoreGeometry, PW, PWCore, PWObjects, Rope, Sisyph
EXPORTS PadFrame =
BEGIN OPEN PadFrame;
Preliminaries
Signal: PUBLIC SIGNAL [message: ROPE] = CODE;
padFrameParamsProp: PUBLIC ATOM ← $PadFrameParams;
PadExtract: PROC [parameters: PadFrameParameters, name: ATOM] RETURNS [cellType: Core.CellType] ~ {
cellType ← Sisyph.ExtractSchematicByName[
name: Rope.Cat[Convert.RopeFromAtom[name, FALSE], "Pad.sch"],
cx: Sisyph.Create[design: GetDesign[parameters]]
];
IF CoreProperties.GetCellTypeProp[cellType, $Layout]=NIL
THEN PWCore.SetGet[cellType, GetDesign[parameters]];
};
GetDesign: PROC [parameters: PadFrameParameters] RETURNS [design: CD.Design] = {
design ← parameters.design;
IF design#NIL THEN RETURN;
design ← PW.OpenDesign[IF parameters.library=NIL THEN "Pads" ELSE parameters.library];
IF design=NIL THEN SIGNAL Signal["Cannot find library"];
parameters.design ← design;
};
Generation of the Core
AddPad: PUBLIC PROC [pads: Pads, public: WR, type: ATOM, pos: NAT, pa1, pa2, pa3, pa4: PA ← []] RETURNS [Pads] ~ {
pas: LIST OF PANIL;
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]];
};
AddPads: PUBLIC PROC [pads: Pads, public: Wire, type: ATOM, firstPos: NAT, reverse: BOOLFALSE, 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: ROPENIL, 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]];
We use the user input to fill padsData
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    =>
inst ← CoreCreate.InstanceList[
PadExtract[parameters, pad.type], CONS [["Pad", pad.public], pad.pas]
];
ENDCASE => 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;
We add the fillers and corners
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;
We compute the transformations for padsData
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, $PadFrame, padFrameParamsProp, parameters];
};
Layout Utilities
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, actual].net;
IF net=NIL THEN {
net ← NEW [Connections.NetRec ← [name: name]]; [] ← Connections.Store[nets, actual, 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 ← PWObjects.CreateCell[instances];
};
Rotate: PROC [padData: PadData] RETURNS [obj: CD.Object] = {
obj ← PW.ChangeOrientation[PWCore.Layout[padData.instance.type], padData.trans.orient];
};
Layout Proc
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.CreateForRefs[];
params: Cabbage.PadRingParams ← NEW [Cabbage.PadRingParamsRec ← [horizLayer: parameters.horizLayer, vertLayer: parameters.vertLayer, opt: noIncompletes, signalSinglePinNets: TRUE]];
dx: INTCD.InterestSize[PWCore.Layout[PadExtract[parameters, $Filler]]].x;
dy: INTCD.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.GetFullWireNames[data.internal, actual].first;
IF NOT IsRoutable[parameters, side, layer] THEN RETURN;
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;
IF side#bottom THEN RETURN;
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
[] ← 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];
};
Decorate Proc
DecoratePadframe: PWCore.DecorateProc = {
SetLazyPins: PROC [wire: Wire] = {CoreGeometry.PutRecordLazyPins[PWCore.extractMode.decoration, wire, cellType]};
parameters: PadFrameParameters ← NARROW [CoreProperties.GetCellTypeProp[cellType, padFrameParamsProp]];
padsData: REF PadsData ← parameters.padsData;
dy: INTCD.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;
CoreOps.VisitRootAtomics[cellType.public, SetLazyPins];
};
Initialization
[] ← PWCore.RegisterLayoutAtom[$PadFrame, LayoutPadFrame, DecoratePadframe];
END.