IFUPWContXlate.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Derived from: PWRoute.XferPins
Last Edited by: Curry, January 24, 1986 4:05:18 pm PST
DIRECTORY
CD,
CDBasics,
CDCells,
CDDirectory,
CDFrame,
CDInstances,
CDOrient,
CDPinObjects,
CDRects,
CDSimpleRules,
IFUPWControl,
PW,
PWPins,
Rope;
IFUPWContXlate: CEDAR PROGRAM    
IMPORTS CD, CDBasics, CDCells, CDDirectory, CDFrame, CDInstances, CDOrient, CDPinObjects, CDRects, CDSimpleRules, PW, PWPins, Rope EXPORTS IFUPWControl =
BEGIN
TrackSeq:  TYPE = RECORD[cSz, tSz, length: INT, seq: SEQUENCE size: CARDINAL OF Track];
Track:   TYPE = RECORD[pos, cost, chan: INT ← 0, pin: REF Pin]; -- pos is center of track
PinSeq:  TYPE = RECORD[SEQUENCE size: CARDINAL OF REF Pin];
Pin:   TYPE = RECORD[pos, size: INT, layer: CD.Layer ← 0, name: Rope.ROPE ← NIL];
SideOrient: PROC[side: IFUPWControl.Side] RETURNS[orientation: CD.Orientation] = {
orientation ← SELECT side FROM
bottom => CDOrient.rotate270,
right => CDOrient.original,
top => CDOrient.rotate90,
left => CDOrient.rotate180, ENDCASE => ERROR};
SideXfrm: PROC[from, to: IFUPWControl.Side] RETURNS[CD.Orientation] =
{RETURN[CDOrient.ComposeOrient
[CDOrient.InverseOrient[SideOrient[from]],  SideOrient[to] ] ]};
NormalPin: PROC[inst: CD.Instance, obj: CD.Object, from, to: IFUPWControl.Side]
RETURNS[pin: REF Pin] = {
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: CDPinObjects.GetLayer[inst], name: CDPinObjects.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[obj: CD.Object, from, to: IFUPWControl.Side]
RETURNS[list: LIST OF REF Pin] = {
pinProc: PWPins.InstanceEnumerator = {
pin: REF Pin ← NormalPin[inst, obj, from, to];
IF pin=NIL THEN RETURN;
list ← CONS[pin, list]};
[] ← PWPins.EnumerateEdgePins[obj, pinProc]};
GetLayer: PROC[list: LIST OF REF Pin, testRope: Rope.ROPE, case: BOOLFALSE]
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 REF Pin, testRope: Rope.ROPE, keepIfFound, case: BOOLFALSE]
RETURNS[LIST OF REF Pin] = {
IF list=NIL THEN RETURN[NIL];
IF (Rope.Find[testRope, list.first.name, 0, case]#-1)=keepIfFound
THEN {list.rest ← DelOthers[list.rest, testRope, keepIfFound, case]; RETURN[list]}
ELSE   RETURN[ DelOthers[list.rest, testRope, keepIfFound, case] ] };
Sort: PROC[list: LIST OF REF Pin] RETURNS[LIST OF REF Pin] = {
SwapREFs: TYPE = RECORD[r0, r1: REF Pin];
IF list=NIL THEN RETURN[NIL];
list.rest ← Sort[list.rest];
FOR temp: LIST OF REF Pin ← list, temp.rest WHILE temp.rest#NIL DO
IF temp.first.pos < temp.rest.first.pos THEN RETURN[list];
[temp.first, temp.rest.first] ← SwapREFs[temp.rest.first, temp.first];
ENDLOOP;
RETURN[list]};
MakeTracks: PROC[cellSize, trackSize, trackGap, chanWidth: INT, vg: LIST OF REF Pin]
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:  REF Pin ← NEW[Pin ← [pos: 0, size: 0]];
last:  REF Pin ← first;
FOR list: LIST OF REF Pin ← vg, list.rest WHILE list#NIL DO
t: INT ← (list.first.pos - list.first.size/2);
b: INT ← (last.pos  + last.size/2);
count ← count + TracksIn[t,b];
last ← list.first;
REPEAT FINISHED => {count ← count + TracksIn[cellSize, last.pos + last.size/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  ← NEW[Pin ← [0, 0, 0, NIL]];
next    ← 1;
last ← first;
FOR list: LIST OF REF Pin ← vg, list.rest WHILE list#NIL DO
next ← InsertSegment[nxt: next, top: (list.first.pos - list.first.size/2), bot: last.pos + last.size/2];
last ← list.first;
REPEAT FINISHED => {next ← InsertSegment[nxt: next, top: cellSize, bot: last.pos+ last.size/2]}
ENDLOOP;
IF next+1#tracks.size THEN ERROR;
tracks[next].pos ← 2*cellSize;
tracks[next].cost ← 0;
tracks[next].pin ← NEW[Pin ← [cellSize, 0, 0, NIL]]};
AssignPinsToTracks: PROC[list: LIST OF REF Pin, tracks: REF TrackSeq] = {
top: INT ← 0;
cnt: INT ← 0;
pin: REF Pin ← tracks[tracks.size-1].pin;
FOR temp: LIST OF REF Pin ← list, temp.rest WHILE temp#NIL DO cnt ← cnt+1 ENDLOOP;
IF cnt > tracks.size-2 THEN ERROR;
FOR temp: LIST OF REF Pin ← list, temp.rest WHILE temp#NIL DO
bot: INT;
FOR top ← top, top+1 DO
currDist: INTABS[temp.first.pos - tracks[top].pos];
nextDist: INTABS[temp.first.pos - 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#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.pos-tracks[bot-1].pos] - ABS[tracks[bot].pin.pos-tracks[bot].pos];
ENDLOOP;
tracks[top+1].pin←NIL;
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=NIL THEN LOOP;
lastDist ← ABS[tracks[track].pin.pos - tracks[track-1].pos] /tracks.tSz;
nextDist ← ABS[tracks[track].pin.pos - tracks[track+1].pos] /tracks.tSz;
IF lastDist=0 AND tracks[track-1].pin=NIL
THEN {tracks[track].pos←tracks[track].pin.pos; LOOP};
IF nextDist=0 AND tracks[track+1].pin=NIL
THEN {tracks[track].pos←tracks[track].pin.pos; LOOP};
ENDLOOP};
AssignChannelsToTrackPins: PROC[tracks: REF TrackSeq] = {
chan: INT ← 0;
FOR track: INT IN [1..tracks.size-1) DO
IF tracks[track].pin=NIL THEN LOOP;
IF ABS[tracks[track].pin.pos - 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=NIL THEN LOOP;
IF tracks[track].pin.pos <= tracks[track].pos
THEN chan ← 0
ELSE {
IF tracks[track].pin.pos  > tracks[track+1].pos - tracks.tSz OR
tracks[track-1].pin#NIL AND (tracks[track-1].pin.pos > 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=NIL THEN LOOP;
IF tracks[track].pin.pos >= tracks[track].pos
THEN chan ← 0
ELSE {
IF tracks[track].pin.pos  < tracks[track-1].pos + tracks.tSz OR
tracks[track+1].pin#NIL AND (tracks[track+1].pin.pos < tracks[track].pos + tracks.tSz)
THEN {tracks[track].chan ← chan; chan ← chan +1} };
ENDLOOP };
FlowRoute: PROC
[design: CD.Design, vg: LIST OF REF Pin, vLayer, gLayer: CD.Layer, tracks: REF TrackSeq]
RETURNS[cell: CD.Object] = {
pol:  CD.Layer ← CDSimpleRules.GetLayer[design.technology.key, "poly"];
met:  CD.Layer ← CDSimpleRules.GetLayer[design.technology.key, "metal"];
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;
cell     ← 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: INTMIN[totSz/4, cSize];
[] ← PW.IncludeInCell[cell,
CDRects.CreateRect[[totSz, vg.first.size], layer], [0,   vg.first.pos - vg.first.size/2]];
pinObj ← CDPinObjects.CreatePinOb[[pinSz, vg.first.size]];
pinInstLt ← PW.IncludeInCell[cell, pinObj, [0,    vg.first.pos - vg.first.size/2]];
pinInstRt ← PW.IncludeInCell[cell, pinObj, [totSz-pinSz, vg.first.pos - vg.first.size/2]];
CDPinObjects.SetName[pinInstLt, vg.first.name];
CDPinObjects.SetName[pinInstRt, vg.first.name];
CDPinObjects.SetLayer[pinInstLt, layer];
CDPinObjects.SetLayer[pinInstRt, layer];
ENDLOOP;
pinObj ← CDPinObjects.CreatePinOb[ [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=NIL THEN LOOP;
[] ← PW.IncludeInCell[cell, CDRects.CreateRect[[rsl, polSz], pol], [lsl, t.pos - polSz/2]];
IF t.chan>-1 THEN {
[] ← PW.IncludeInCell[cell, CDRects.CreateRect[[lsl, polSz], pol], [0, t.pin.pos - polSz/2]];
[] ← PW.IncludeInCell[cell, CDRects.CreateRect[[polSz, ABS[t.pos-t.pin.pos]+polSz],  pol],
[lsl-polSz, MIN[t.pos, t.pin.pos] - polSz/2]]};
pinInstLt ← PW.IncludeInCell[cell, pinObj, [0,      t.pin.pos - polSz/2]];
pinInstRt ← PW.IncludeInCell[cell, pinObj, [totSz-pinObj.size.x, t.pos  - polSz/2]];
CDPinObjects.SetName[pinInstLt, t.pin.name];
CDPinObjects.SetName[pinInstRt, t.pin.name];
CDPinObjects.SetLayer[pinInstLt, pol];
CDPinObjects.SetLayer[pinInstRt, pol];
ENDLOOP;
CDCells.SetInterestRect[cell, [0, 0, totSz, tracks.length]];
IF NOT CDCells.RepositionCell[cell, NIL] THEN Signal[];
IF NOT CDDirectory.Include[design, cell, CDFrame.ID["MergeNrml"]] THEN Signal[]};
PW.IncludeInDirectory[design, cell, CDFrame.ID["MergeNrml"]]};
Signal: SIGNAL = CODE;
MergePwrPins: PUBLIC PROC [
design:    CD.Design,
vgTemplate:   PW.Object,
pinTemplate:   PW.Object,
pinTemplateSide: IFUPWControl.Side,
routingLayerDes: Rope.ROPENIL,
minWidth:   INT ← 0]
RETURNS [cell: PW.Object ← NIL] = {
pol:  CD.Layer ← CDSimpleRules.GetLayer[design.technology.key, "poly"];
met:  CD.Layer ← CDSimpleRules.GetLayer[design.technology.key, "metal"];
met2:  CD.Layer ← CDSimpleRules.GetLayer[design.technology.key, "metal2"];
chanWidth: INT ← CDSimpleRules.MinDist[pol, pol] + CDSimpleRules.MinWidth[pol];
trackSize:  INT ← CDSimpleRules.Contact[met, met2].size.x;
trackGap:  INT ← CDSimpleRules.MinDist[met2, met2];
cellSize: INT;
xfer:  PW.Object;
tracks: REF TrackSeq;
pins:  LIST OF REF Pin ← LoadNormalPinList[
obj: pinTemplate, from:        pinTemplateSide, to: right];
vg:  LIST OF REF Pin ← LoadNormalPinList[
obj: vgTemplate,  from: CDFrame.OppSide[ pinTemplateSide], to: left];
vLayer: CD.Layer;
gLayer: CD.Layer;
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, testRope: "VDD GND", keepIfFound: TRUE, case: FALSE];
pins  ← DelOthers[list: pins, testRope: "VDD GND", keepIfFound: FALSE, case: FALSE];
vg   ← Sort[vg];
pins  ← Sort[pins];
IF routingLayerDes=NIL THEN routingLayerDes ← "metal2";
cellSize    ← CDBasics.SizeOfRect[CDOrient.MapRect[
itemInCell:  CD.InterestRect[pinTemplate],
cellSize:   pinTemplate.size,
cellInstOrient: SideXfrm[pinTemplateSide, right],
cellInstPos:  [0,0] ] ].y;
tracks    ← MakeTracks[cellSize, trackSize, trackGap, chanWidth, vg];
AssignPinsToTracks[pins, tracks];
AllignSparseTracks[tracks];
AssignChannelsToTrackPins[tracks];
cell ← FlowRoute[design, vg, vLayer, gLayer, tracks];
xfer ← XferPins[design, cell, right, routingLayerDes, MAX[0, minWidth-cell.size.x]];
cell ← PW.AbutX[design, cell, xfer];
IF pinTemplateSide#right THEN
cell ← PW.ChangeOrientation[design, cell, SideXfrm[right, pinTemplateSide]];
PW.RenameObject[design, cell, CDFrame.ID["Merge"]]};
XferPins: PUBLIC PROC [
design:    CD.Design,
template:    PW.Object,
objSide:    IFUPWControl.Side,
routingLayerDes: Rope.ROPE,
minWidth:   INT]
RETURNS [cell: PW.Object ← NIL] = {
IncludeXferPin: PROC[pin: REF Pin] = {
InclRct: PROC[layer: CD.Layer, size, pos: CD.Position] =
{IF size.x>0 THEN [] ← PW.IncludeInCell[cell, 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[cell, contact, [pos.x, pos.y+fill/2]]; RETURN};
DO
[] ← PW.IncludeInCell[cell, 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.size, cSize];
posYLt:  INT   ← pin.pos-pin.size/2;
posYRt:  INT   ← pin.pos-sizeY/2;
pinObjLt: CD.Object ← CDPinObjects.CreatePinOb[[MIN[pin.size, minWidth/2], pin.size]];
pinObjRt: CD.Object ← CDPinObjects.CreatePinOb[[MIN[sizeY,  minWidth/2], sizeY]];
pinInstLt:  CD.Instance;
pinInstRt:  CD.Instance;
route:   CD.Layer ← (IF routeRef=CD.combined 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.size], [0,    posYLt]];
pinObjRt ← pinObjLt;
posYRt ← posYLt};
level3   => { -- this one is three level
sizeX:  INT ← offset + cSize + gap + cSize;
InclRct[ pin.layer,   [offset + cSize,   pin.size], [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.size], [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.size], [0,    posYLt]];
Stitch[ pin.layer, route,           [sizeX-cSize, posYRt]];
InclRct[ route,    [minWidth-sizeX+cSize, sizeY], [sizeX-cSize, posYRt]]};
pinInstLt ← PW.IncludeInCell[cell, pinObjLt, [0,         posYLt]];
pinInstRt ← PW.IncludeInCell[cell, pinObjRt, [minWidth-pinObjRt.size.x, posYRt]];
CDPinObjects.SetName[pinInstLt, pin.name];
CDPinObjects.SetName[pinInstRt, pin.name];
CDPinObjects.SetLayer[pinInstLt, pin.layer];
CDPinObjects.SetLayer[pinInstRt, route] };
pol:  CD.Layer ← CDSimpleRules.GetLayer[design.technology.key, "poly"];
met:  CD.Layer ← CDSimpleRules.GetLayer[design.technology.key, "metal"];
met2:  CD.Layer ← CDSimpleRules.GetLayer[design.technology.key, "metal2"];
routeRef: CD.Layer ← IF routingLayerDes=NIL
THENCD.combined
ELSE CDSimpleRules.GetLayer[design.technology.key, routingLayerDes];
offset:   INT ← CDSimpleRules.MinDist[met2, met2];
gap:   INT ← 2 * design.technology.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 REF Pin;
IF template = NIL THEN ERROR;
pins ← LoadNormalPinList[template, objSide, right];
IF pins=NIL THEN Signal[];
FOR list: LIST OF REF Pin ← pins, list.rest WHILE list#NIL DO
maxLevel ← MAX[ maxLevel, SELECT TRUE FROM
routeRef=CD.combined      => 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];
cell ← PW.CreateEmptyCell[];
FOR list: LIST OF REF Pin ← pins, list.rest WHILE list#NIL DO
IncludeXferPin[list.first] ENDLOOP;
height ← SELECT objSide FROM
left, right => CD.InterestSize[template].y, ENDCASE => CD.InterestSize[template].x;
CDCells.SetInterestRect[cell, [0, 0, minWidth, height]];
PW.IncludeInDirectory[design, cell, CDFrame.ID["XlateNrml"]];
IF NOT CDCells.RepositionCell[cell, NIL] THEN Signal[];
IF NOT CDDirectory.Include[design, cell, CDFrame.ID["XlateNrml"]] THEN Signal[];
IF objSide#right THEN
cell ← PW.ChangeOrientation[design, cell, SideXfrm[right, objSide]];
PW.RenameObject[design, cell, CDFrame.ID[(IF maxLevel=1 THEN "Ext" ELSE "Xlate")]]};
END.