CoreGlueXlate.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Derived from: PWRoute.XferPins
Last Edited by: Curry, August 18, 1986 4:50:36 pm PDT
Last Edited by: Louis Monier February 10, 1987 7:25:19 pm PST
DIRECTORY
CCDUtils, CD, CDBasics, CDCells, CDRects, CDSimpleRules, CDSymbolicObjects, Core, CoreBlock, CoreFrame, CoreGlue, CoreLibrary, CoreName, IO, PW, PWC, Rope;
CoreGlueXlate:
CEDAR
PROGRAM
IMPORTS CCDUtils, CD, CDBasics, CDCells, CDRects, CDSimpleRules, CDSymbolicObjects, CoreBlock, CoreFrame, CoreLibrary, CoreName, IO, PW, PWC, Rope
EXPORTS CoreGlue =
BEGIN
TrackSeq: TYPE = RECORD[cSz, tSz, length: INT, seq: SEQUENCE size: CARDINAL OF Track];
Track: TYPE = RECORD[pos, cost, chan: INT ← 0, pin: NWMML]; -- pos is center of track
Side: TYPE = CoreFrame.Side;
NWMML: TYPE = PWC.NWMML;
ROPE: TYPE = Rope.ROPE;
CellType: TYPE = Core.CellType;
GND: ROPE ← CoreName.RopeNm["GND"];
VDD: ROPE ← CoreName.RopeNm["VDD"];
pol: CD.Layer ← CDSimpleRules.GetLayer[$cmosB, "poly"];
met: CD.Layer ← CDSimpleRules.GetLayer[$cmosB, "metal"];
met2: CD.Layer ← CDSimpleRules.GetLayer[$cmosB, "metal2"];
SideOrient:
PROC[side: Side]
RETURNS[orientation:
CD.Orientation] = {
orientation ←
SELECT side
FROM
bottom => rotate270,
right => original,
top => rotate90X,
left => mirrorX, ENDCASE => ERROR};
SideXfrm:
PROC[from, to: Side]
RETURNS[
CD.Orientation] =
{
RETURN[CDBasics.ComposeOrient
[CDBasics.InverseOrient[SideOrient[from]], SideOrient[to] ] ]};
NormalPin: PROC[inst: CD.Instance, obj: CD.Object, from, to: Side]
RETURNS[pin: NWMML] = {
objIR: CD.Rect ← CDOrient.MapRect[
itemInCell: CD.InterestRect[obj], -- uses inst.orientation
cellSize: obj.size,
cellInstOrient: SideXfrm[from, to],
cellInstPos: [0,0] ];
rect: CD.Rect ← CDOrient.MapRect[
itemInCell: CDInstances.InstRectO[inst], -- uses inst.orientation
cellSize: obj.size,
cellInstOrient: SideXfrm[from, to],
cellInstPos: [0,0] ];
IF PWPins.GetSide[obj, inst].side#from THEN RETURN[NIL];
pin ← NEW[Pin ←
[pos: 0, size: 0, layer: CDSymbolicObjects.GetLayer[inst], name: CDSymbolicObjects.GetName[inst] ] ];
pin.pos ← SELECT to FROM
top, bottom => (rect.x2 + rect.x1)/2 - objIR.x1,
ENDCASE => (rect.y2 + rect.y1)/2 - objIR.y1;
pin.size ← SELECT to FROM
top, bottom => rect.x2-rect.x1,
ENDCASE => rect.y2-rect.y1};
LoadNormalPinList: PROC[cell: CellType, from, to: Side]
RETURNS[list: LIST OF NWMML] = {
pinProc: PWPins.InstanceEnumerator = {
pin: NWMML ← NormalPin[inst, obj, from, to];
IF pin=NIL THEN RETURN;
list ← CONS[pin, list]};
[] ← PWPins.EnumerateEdgePins[obj, pinProc]};
LoadNormalPinList:
PROC[cell: CellType, side: Side, minSep:
INT]
RETURNS[list: LIST OF NWMML] = {
cellName: ROPE ← CoreName.CellNm[cell].n;
list ← CCDUtils.SidePinList[cell, side];
FOR temp:
LIST
OF
NWMML ← list, temp.rest
WHILE temp.rest#
NIL
DO
sep: INT ← temp.rest.first.min - temp.first.max;
diff: INT ← minSep - sep;
IF temp.first.wire # temp.rest.first.wire
AND
temp.first.layer = temp.rest.first.layer AND
diff > 0
THEN {
log.PutF["\nMinimum separation adjustment HACK; %g: %g %g",
IO.rope[cellName], IO.rope[temp.first.name], IO.rope[temp.rest.first.name]];
temp.first.max ← temp.first.max - diff/2;
temp.rest.first.min ← temp.rest.first.min + diff/2};
ENDLOOP;
FOR temp:
LIST
OF
NWMML ← list, temp.rest
WHILE temp#
NIL
DO
temp.first.max ← temp.first.max-temp.first.min; -- size
temp.first.min ← temp.first.min+temp.first.max/2; -- center position
ENDLOOP};
GetLayer:
PROC[list:
LIST
OF
NWMML, testRope:
ROPE, case:
BOOL ←
FALSE]
RETURNS[layer: CD.Layer] = {
IF list=NIL THEN ERROR;
FOR list ← list, list.rest
WHILE list#
NIL
DO
IF Rope.Find[testRope, list.first.name, 0, case]#-1 THEN RETURN[list.first.layer] ENDLOOP;
ERROR};
DelOthers:
PROC
[list: LIST OF NWMML, testRopes: LIST OF ROPE, keepIfFound, case: BOOL ← FALSE]
RETURNS[LIST OF NWMML] = {
found: BOOL ← FALSE;
IF list=NIL THEN RETURN[NIL];
FOR ropes:
LIST
OF
ROPE ← testRopes, ropes.rest
WHILE ropes#
NIL
DO
found ← found OR (Rope.Find[list.first.name, ropes.first, 0, case]#-1) ENDLOOP;
IF found=keepIfFound
THEN {list.rest ← DelOthers[list.rest, testRopes, keepIfFound, case]; RETURN[list]}
ELSE RETURN[ DelOthers[list.rest, testRopes, keepIfFound, case] ] };
Sort:
PROC[list:
LIST
OF
NWMML]
RETURNS[
LIST
OF
NWMML] = {
SwapNWMMLs: TYPE = RECORD[r0, r1: NWMML];
IF list=NIL THEN RETURN[NIL];
list.rest ← Sort[list.rest];
FOR temp:
LIST
OF
NWMML ← list, temp.rest
WHILE temp.rest#
NIL
DO
IF temp.first.min < temp.rest.first.min THEN RETURN[list];
[temp.first, temp.rest.first] ← SwapNWMMLs[temp.rest.first, temp.first];
ENDLOOP;
RETURN[list]};
MakeTracks:
PROC[cellSize, trackSize, trackGap, chanWidth:
INT, vg:
LIST
OF
NWMML]
RETURNS[tracks: REF TrackSeq] = {
TracksIn:
PROC[top, bot:
INT]
RETURNS[
INT] =
{RETURN[MAX[(top-bot-trackGap)/(trackSize+trackGap), 0]]};
InsertSegment:
PROC[nxt, top, bot:
INT]
RETURNS[
INT]= {
cnt: INT ← TracksIn[top, bot];
FOR nxt ← nxt, nxt+1
WHILE cnt>0
DO
tracks[nxt].pos ← bot + trackGap + trackSize/2;
bot ← bot + trackGap + trackSize;
cnt ← cnt -1; ENDLOOP;
RETURN[nxt]};
count: INT ← 0;
next: INT ← 0;
first: NWMML ← [min: 0, max: 0];
last: NWMML ← first;
FOR list:
LIST
OF
NWMML ← vg, list.rest
WHILE list#
NIL
DO
t: INT ← (list.first.min - list.first.max/2);
b: INT ← (last.min + last.max/2);
count ← count + TracksIn[t,b];
last ← list.first;
REPEAT FINISHED => {count ← count + TracksIn[cellSize, last.min + last.max/2]} ENDLOOP;
tracks ← NEW[TrackSeq[count+2]];
tracks.tSz ← trackSize + trackGap;
tracks.cSz ← chanWidth;
tracks.length ← cellSize;
tracks[0].pos ← 0;
tracks[0].cost ← cellSize*(cellSize/tracks.tSz);
tracks[0].pin ← ["Dummy", NIL, 0, 0, 0];
next ← 1;
last ← first;
FOR list:
LIST
OF
NWMML ← vg, list.rest
WHILE list#
NIL
DO
next ← InsertSegment[nxt: next, top: (list.first.min - list.first.max/2), bot: last.min + last.max/2];
last ← list.first;
REPEAT FINISHED => {next ← InsertSegment[nxt: next, top: cellSize, bot: last.min+ last.max/2]}
ENDLOOP;
IF next+1#tracks.size THEN ERROR;
tracks[next].pos ← 2*cellSize;
tracks[next].cost ← 0;
tracks[next].pin ← ["Dummy", NIL, cellSize, 0, 0]};
AssignPinsToTracks:
PROC[list:
LIST
OF
NWMML, tracks:
REF TrackSeq] = {
top: INT ← 0;
cnt: INT ← 0;
pin: NWMML ← tracks[tracks.size-1].pin;
FOR temp: LIST OF NWMML ← list, temp.rest WHILE temp#NIL DO cnt ← cnt+1 ENDLOOP;
IF cnt > tracks.size-2 THEN ERROR;
FOR temp:
LIST
OF
NWMML ← list, temp.rest
WHILE temp#
NIL
DO
bot: INT;
FOR top ← top, top+1
DO
currDist: INT ← ABS[temp.first.min - tracks[top].pos];
nextDist: INT ← ABS[temp.first.min - tracks[top+1].pos];
IF top+1 = tracks.size-1 THEN EXIT;
IF nextDist - currDist > tracks[top].cost THEN EXIT;
ENDLOOP;
tracks[top+1].pin←temp.first; -- temporary
FOR bot ← top, bot-1 WHILE tracks[bot].pin.name#NIL DO ENDLOOP;
FOR bot ← bot, bot+1
WHILE bot<=top
DO
tracks[bot].pin ← tracks[bot+1].pin;
tracks[bot].cost ← tracks[bot-1].cost
+ ABS[tracks[bot].pin.min-tracks[bot-1].pos] - ABS[tracks[bot].pin.min-tracks[bot].pos];
ENDLOOP;
tracks[top+1].pin← [ ];
ENDLOOP;
tracks[tracks.size-1].pin ← pin};
AllignSparseTracks:
PROC[tracks:
REF TrackSeq] = {
FOR track:
INT
IN [1..tracks.size-1)
DO
lastDist, nextDist: INT;
IF tracks[track].pin.name=NIL THEN LOOP;
lastDist ← ABS[tracks[track].pin.min - tracks[track-1].pos] /tracks.tSz;
nextDist ← ABS[tracks[track].pin.min - tracks[track+1].pos] /tracks.tSz;
IF lastDist=0
AND tracks[track-1].pin.name=
NIL
THEN {tracks[track].pos←tracks[track].pin.min; LOOP};
IF nextDist=0
AND tracks[track+1].pin.name=
NIL
THEN {tracks[track].pos←tracks[track].pin.min; LOOP};
ENDLOOP};
AssignChannelsToTrackPins:
PROC[tracks:
REF TrackSeq] = {
chan: INT ← 0;
FOR track:
INT
IN [1..tracks.size-1)
DO
IF tracks[track].pin.name=NIL THEN LOOP;
IF ABS[tracks[track].pin.min - tracks[track-1].pos]=0 THEN tracks[track].chan ← -1
ENDLOOP;
chan ← 0;
FOR track:
INT
IN [1..tracks.size-1)
DO
IF tracks[track].pin.name=NIL THEN LOOP;
IF tracks[track].pin.min <= tracks[track].pos
THEN chan ← 0
ELSE {
IF tracks[track].pin.min > tracks[track+1].pos - tracks.tSz
OR
tracks[track-1].pin.name#
NIL
AND (tracks[track-1].pin.min > tracks[track].pos - tracks.tSz)
THEN {tracks[track].chan ← chan; chan ← chan +1} };
ENDLOOP;
chan ← 0;
FOR track:
INT
DECREASING
IN [1..tracks.size-1)
DO
IF tracks[track].pin.name=NIL THEN LOOP;
IF tracks[track].pin.min >= tracks[track].pos
THEN chan ← 0
ELSE {
IF tracks[track].pin.min < tracks[track-1].pos + tracks.tSz
OR
tracks[track+1].pin.name#
NIL
AND (tracks[track+1].pin.min < tracks[track].pos + tracks.tSz)
THEN {tracks[track].chan ← chan; chan ← chan +1} };
ENDLOOP };
FlowRoute:
PROC [vg:
LIST
OF
NWMML, vLayer, gLayer:
CD.Layer, tracks:
REF TrackSeq]
RETURNS[cell: CellType ←
NIL] = {
RETURN[CoreLibrary.ObjCell[
FlowRouteObj[vg, vLayer, gLayer, tracks], CoreName.ID["Flow"] ] ] };
FlowRouteObj:
PROC [vg:
LIST
OF
NWMML, vLayer, gLayer:
CD.Layer, tracks:
REF TrackSeq]
RETURNS[obj: CD.Object] = {
pinObj: CD.Object;
pinInstLt: CD.Instance;
pinInstRt: CD.Instance;
cSize: INT ← CDSimpleRules.Contact[met, pol].size.x;
chnSz: INT ← tracks.cSz;
polSz: INT ← CDSimpleRules.MinWidth[pol];
nChans: INT ← 0;
totSz: INT ← 0;
obj ← PW.CreateEmptyCell[];
FOR track: INT IN [1..tracks.size-1) DO nChans ← MAX[nChans, tracks[track].chan+1] ENDLOOP;
totSz ← ((nChans*chnSz + 2*polSz -1)/polSz)*polSz; -- +polSz +round up to next polSz
FOR vg ← vg, vg.rest
WHILE vg#
NIL
DO
layer: CD.Layer ← IF Rope.Equal[vg.first.name, VDD, FALSE] THEN vLayer ELSE gLayer;
pinSz: INT ← MIN[totSz/4, cSize];
[] ←
PW.IncludeInCell[obj,
CDRects.CreateRect[[totSz, vg.first.max], layer], [0, vg.first.min - vg.first.max/2]];
pinObj ← CDSymbolicObjects.CreatePin[[pinSz, vg.first.max]];
pinInstLt ← PW.IncludeInCell[obj, pinObj, [0, vg.first.min - vg.first.max/2]];
pinInstRt ← PW.IncludeInCell[obj, pinObj, [totSz-pinSz, vg.first.min - vg.first.max/2]];
CDSymbolicObjects.SetName[pinInstLt, vg.first.name];
CDSymbolicObjects.SetName[pinInstRt, vg.first.name];
CDSymbolicObjects.SetLayer[pinInstLt, layer];
CDSymbolicObjects.SetLayer[pinInstRt, layer];
ENDLOOP;
pinObj ← CDSymbolicObjects.CreatePin[ [polSz, polSz] ];
FOR track:
INT
IN [1..tracks.size-1)
DO
t: Track ← tracks[track];
lsl: INT ← chnSz + t.chan*chnSz; -- left segment length
rsl: INT ← totSz - lsl; -- right segment length
IF t.pin.name=NIL THEN LOOP;
[] ← PW.IncludeInCell[obj, CDRects.CreateRect[[rsl, polSz], pol], [lsl, t.pos - polSz/2]];
IF t.chan>-1
THEN {
[] ← PW.IncludeInCell[obj, CDRects.CreateRect[[lsl, polSz], pol], [0, t.pin.min - polSz/2]];
[] ←
PW.IncludeInCell[obj, CDRects.CreateRect[[polSz,
ABS[t.pos-t.pin.min]+polSz], pol],
[lsl-polSz, MIN[t.pos, t.pin.min] - polSz/2]]};
pinInstLt ← PW.IncludeInCell[obj, pinObj, [0, t.pin.min - polSz/2]];
pinInstRt ← PW.IncludeInCell[obj, pinObj, [totSz-pinObj.size.x, t.pos - polSz/2]];
CDSymbolicObjects.SetName[pinInstLt, t.pin.name];
CDSymbolicObjects.SetName[pinInstRt, t.pin.name];
CDSymbolicObjects.SetLayer[pinInstLt, pol];
CDSymbolicObjects.SetLayer[pinInstRt, pol];
ENDLOOP;
CDCells.SetInterestRect[obj, [0, 0, totSz, tracks.length]];
IF NOT CDCells.RepositionCell[obj, NIL] THEN Signal[]};
Signal: SIGNAL = CODE;
MergePwrPins:
PUBLIC
PROC [
vgTemplate: CellType,
pinTemplate: CellType,
pinTemplateSide: Side,
routingLayerDes: ROPE ← NIL,
minWidth:
INT ← 0]
RETURNS [cell: CellType ← NIL] = {
chanWidth: INT ← CDSimpleRules.MinDist[pol, pol] + CDSimpleRules.MinWidth[pol];
trackSize: INT ← CDSimpleRules.Contact[met, met2].size.x;
trackGap: INT ← CDSimpleRules.MinDist[met2, met2];
vgTemplateSide: Side ← CoreFrame.OppSide[ pinTemplateSide];
cellSize: INT;
tracks: REF TrackSeq;
offset: INT ← CDSimpleRules.MinDist[met2, met2];
pins: LIST OF NWMML ← LoadNormalPinList[pinTemplate, pinTemplateSide, offset];
vg: LIST OF NWMML ← LoadNormalPinList[vgTemplate, vgTemplateSide, offset];
vLayer: CD.Layer;
gLayer: CD.Layer;
flow: CellType;
xfer: CellType;
IF pins = NIL OR vg = NIL THEN {cell ← NIL; Signal[]; RETURN[cell]};
vLayer ← GetLayer[list: pins, testRope: VDD, case: FALSE];
gLayer ← GetLayer[list: pins, testRope: GND, case: FALSE];
vg ← DelOthers[list: vg, testRopes: LIST[GND, VDD], keepIfFound: TRUE, case: FALSE];
pins ← DelOthers[list: pins, testRopes: LIST[GND, VDD], keepIfFound: FALSE, case: FALSE];
vg ← Sort[vg];
pins ← Sort[pins];
IF routingLayerDes=NIL THEN routingLayerDes ← "metal2";
cellSize ← CDBasics.SizeOfRect[CDBasics.MapRect[
itemInCell: PWC.InterestRect[pinTemplate],
cellSize: PWC.InterestSize[pinTemplate],
cellInstOrient: SideXfrm[pinTemplateSide, right],
cellInstPos: [0,0] ] ].y;
tracks ← MakeTracks[cellSize, trackSize, trackGap, chanWidth, vg];
AssignPinsToTracks[pins, tracks];
AllignSparseTracks[tracks];
AssignChannelsToTrackPins[tracks];
flow ← FlowRoute[vg, vLayer, gLayer, tracks];
xfer ← XferPins[flow, right, routingLayerDes, MAX[0, minWidth-PWC.InterestSize[flow].x]];
cell ← CoreBlock.AbutCellList[CoreName.ID["MrgPwr"], left, LIST[flow, xfer]];
IF pinTemplateSide#right
THEN
cell ← CoreFrame.RotateCellType[cell, SideXfrm[right, pinTemplateSide]]};
IF pinTemplateSide#right THEN
merg ← PW.ChangeOrientation[merg, SideXfrm[right, pinTemplateSide]];
cell ← CoreLibrary.ObjCell[merg, CoreName.ID["MrgPwr"] ]};
XferPins:
PUBLIC
PROC [
template: CellType,
objSide: Side,
routingLayerDes: ROPE,
minWidth:
INT]
RETURNS [cell: CellType ←
NIL] = {
RETURN[CoreLibrary.ObjCell[
XferPinsObj[template, objSide, routingLayerDes, minWidth], CoreName.ID["Xlt"] ] ] };
XferPinsObj:
PROC [
template: CellType,
objSide: Side,
routingLayerDes: ROPE,
minWidth:
INT]
RETURNS [obj: CD.Object ← NIL] = {
IncludeXferPin:
PROC[pin:
NWMML] = {
InclRct:
PROC[layer:
CD.Layer, size, pos:
CD.Position] =
{IF size.x>0 THEN [] ← PW.IncludeInCell[obj, CDRects.CreateRect[size, layer], pos]};
Stitch:
PROC [layer1, layer2:
CD.Layer, pos:
CD.Position] = {
contact: PW.Object ← CDSimpleRules.Contact[layer1, layer2];
additional: INT ← (sizeY-cSize)/(cSize+gap);
fill: INT ← sizeY - (1+additional)*cSize;
IF additional=0 THEN {[] ← PW.IncludeInCell[obj, contact, [pos.x, pos.y+fill/2]]; RETURN};
DO
[] ← PW.IncludeInCell[obj, contact, pos];
IF additional=0 THEN RETURN;
pos.y ← pos.y + cSize + fill/additional;
fill ← fill - fill/additional;
additional ← additional -1;
ENDLOOP};
sizeY: INT ← MAX[pin.max, cSize];
posYLt: INT ← pin.min-pin.max/2;
posYRt: INT ← pin.min-sizeY/2;
pinObjLt: CD.Object ← CDSymbolicObjects.CreatePin[[MIN[pin.max, minWidth/2], pin.max]];
pinObjRt: CD.Object ← CDSymbolicObjects.CreatePin[[MIN[sizeY, minWidth/2], sizeY]];
pinInstLt: CD.Instance;
pinInstRt: CD.Instance;
route: CD.Layer ← (IF routeRef=CD.undefLayer THEN pin.layer ELSE routeRef);
level3: BOOL ← pin.layer=pol AND route=met2 OR pin.layer=met2 AND route=pol;
SELECT
TRUE
FROM
pin.layer=route => {
-- this one is one level
InclRct[ route, [minWidth, pin.max], [0, posYLt]];
pinObjRt ← pinObjLt;
posYRt ← posYLt};
level3 => {
-- this one is three level
sizeX: INT ← offset + cSize + gap + cSize;
InclRct[ pin.layer, [offset + cSize, pin.max], [0, posYLt]];
Stitch[ pin.layer, met, [offset, posYRt]];
InclRct[ met, [2*cSize+gap, sizeY], [offset, posYRt]];
Stitch[ met, route, [sizeX-cSize, posYRt]];
InclRct[ route, [minWidth-sizeX+cSize, sizeY], [sizeX-cSize, posYRt]]};
maxLevel=3 => {
-- this one is two level and maxLevel=3
sizeX: INT ← offset + cSize + gap + cSize;
InclRct[ pin.layer, [offset+2*cSize+gap, pin.max], [0, posYLt]];
Stitch[ pin.layer, route, [sizeX-cSize, posYRt]];
InclRct[ route, [minWidth-sizeX+cSize, sizeY], [sizeX-cSize, posYRt]]};
ENDCASE => {
-- this one is two level and maxLevel=2
sizeX: INT ← offset + cSize;
InclRct[ pin.layer, [offset + cSize, pin.max], [0, posYLt]];
Stitch[ pin.layer, route, [sizeX-cSize, posYRt]];
InclRct[ route, [minWidth-sizeX+cSize, sizeY], [sizeX-cSize, posYRt]]};
pinInstLt ← PW.IncludeInCell[obj, pinObjLt, [0, posYLt]];
pinInstRt ← PW.IncludeInCell[obj, pinObjRt, [minWidth-pinObjRt.size.x, posYRt]];
CDSymbolicObjects.SetName[pinInstLt, pin.name];
CDSymbolicObjects.SetName[pinInstRt, pin.name];
CDSymbolicObjects.SetLayer[pinInstLt, pin.layer];
CDSymbolicObjects.SetLayer[pinInstRt, route] };
routeRef:
CD.Layer ←
IF routingLayerDes=
NIL
THEN CD.undefLayer
ELSE CDSimpleRules.GetLayer[$cmosB, routingLayerDes];
offset: INT ← CDSimpleRules.MinDist[met2, met2];
gap: INT ← 2 * CD.FetchTechnology[$cmosB].lambda;
cSize: INT ← CDSimpleRules.Contact[met, met2].size.x;
lay1x: INT ← 0;
lay2x: INT ← 0;
lay3x: INT ← 0;
maxLevel: INT ← 0;
height: INT ← 0;
pins: LIST OF NWMML;
obj ← PW.CreateEmptyCell[];
IF template = NIL THEN ERROR;
pins ← LoadNormalPinList[template, objSide, offset];
IF pins=NIL THEN Signal[];
FOR list:
LIST
OF
NWMML ← pins, list.rest
WHILE list#
NIL
DO
maxLevel ←
MAX[ maxLevel,
SELECT
TRUE
FROM
routeRef=CD.undefLayer => 1,
routeRef=list.first.layer => 1,
list.first.layer=pol AND routeRef=met2 => 3,
list.first.layer=met2 AND routeRef=pol => 3,
ENDCASE => 2 ] ENDLOOP;
minWidth ←
MAX[ minWidth,
SELECT maxLevel
FROM
1 => 0,
2 => offset + cSize,
ENDCASE => offset + cSize + gap + cSize];
IF minWidth=0 THEN RETURN[NIL];
FOR list:
LIST
OF
NWMML ← pins, list.rest
WHILE list#
NIL
DO
IncludeXferPin[list.first] ENDLOOP;
height ←
SELECT objSide
FROM
left, right => PWC.InterestSize[template].y,
ENDCASE => PWC.InterestSize[template].x;
CDCells.SetInterestRect[obj, [0, 0, minWidth, height]];
IF NOT CDCells.RepositionCell[obj, NIL] THEN Signal[];
IF objSide#right
THEN
obj ← PW.ChangeOrientation[obj, SideXfrm[right, objSide]]};
TestMergePwr:
PROC = {
design: CD.Design ← PW.OpenDesign["CoreGlueTest"];
vgTemplateO: CD.Object ← PW.Get[design, "VGTemplate"]; -- center
pinsTemplateO: CD.Object ← PW.Get[design, "PinsTemplate"]; -- top side pads
vgTemplate: CellType ← CoreLibrary.ObjCell[vgTemplateO, "VGTemplate"];
pinsTemplate: CellType ← CoreLibrary.ObjCell[pinsTemplateO, "PinsTemplate"];
merge: CellType ← MergePwrPins[vgTemplate, pinsTemplate, bottom, "metal2"];
mergeO: CD.Object ← PWC.Layout[merge];
combinedO: CD.Object ← PW.AbutListY[LIST[vgTemplateO, mergeO, pinsTemplateO]];
[ ] ← PW.Draw[combinedO];
Signal[]};
log:
IO.
STREAM ← CoreFrame.GetLog[];
END.