CoreRouteChangeLayers.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Don Curry November 8, 1987 12:45:22 pm PST
DIRECTORY
CD, CDBasics, CDInstances, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, Core, CoreClasses, CoreCreate, CoreGeometry, CoreOps, CoreProperties, CoreRoute, IO, PW, PWCore, Rope, Route, Sisyph, SymTab;
CoreRouteChangeLayers: CEDAR PROGRAM
IMPORTS
CD, CDBasics, CDInstances, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, CoreGeometry, CoreOps, CoreProperties, CoreRoute, IO, PW, PWCore, Rope, Sisyph, SymTab =
BEGIN
Types and constants
ChangeLayersForm:   TYPE = CoreRoute.ChangeLayersForm;
ChangeLayersFormAry: TYPE = CoreRoute.ChangeLayersFormAry;
ChangeLayersFormRec:  TYPE = CoreRoute.ChangeLayersFormRec;
WirePin:       TYPE = CoreRoute.WirePin;
WirePins:      TYPE = CoreRoute.WirePins;
Side:       TYPE = CoreGeometry.Side;
changeLayersLayoutProp:  ATOM = $ChangeLayers;
changeLayersLayoutRawProp: ATOM = $RawChangeLayers;
changeLayersFormProp:  ATOM = $ChangeLayersForm;
wireWidthProp:     ATOM = $w;
technologyKey:     ATOM = $cmosB;
lambda:       INT ← CDSimpleRules.GetTechnology[technologyKey].lambda;
L4:         INT ← 4*lambda;
layDeco:       CoreGeometry.Decoration ← PWCore.extractMode.decoration;
schDeco:       CoreGeometry.Decoration ← Sisyph.mode.decoration;
Attribute, Layout and Decorate Procs
Attribute: PWCore.AttributesProc = {
data:  CoreClasses.RecordCellType ← NARROW[cellType.data];
name:  IO.ROPE       ← CoreOps.GetCellTypeName[cellType];
form:  ChangeLayersForm    ← NEW[ChangeLayersFormAry ←[vert:CD.commentLayer]];
subInst: CoreCreate.CellInstance   ← data[0];
subObj: CD.Object  ← PWCore.Layout[subInst.type];
subSize: CD.Position ← CD.InterestSize[subObj];
globals: Core.Wires ← CoreRoute.GlobalWires[cellType];
FOR side: Side IN Side DO
GetBus: PROC[ws: Core.Wires] RETURNS[found: BOOLTRUE] = {
IF ws=NIL THEN RETURN[FALSE];
IF ws.rest#NIL THEN ERROR;
IF form.ary[side].bus#NIL AND form.ary[side].bus # ws.first THEN ERROR;
form.ary[side].bus ← ws.first};
rw: REF INT;
pIR: CD.Rect ← CD.InterestRect[CoreGeometry.GetObject[schDeco, cellType]];
cIR: CD.Rect ← CoreRoute.SchMappedIR[subInst];
min: INT  ← SELECT side FROM
left, right => cIR.y1 - pIR.y1,
top, bottom => cIR.x1 - pIR.x1,
ENDCASE  => ERROR;
max: INT  ← SELECT side FROM
left, right => cIR.y2 - pIR.y1,
top, bottom => cIR.x2 - pIR.x1,
ENDCASE  => ERROR;
wires: Core.Wires ← CoreRoute.OrderedAtomicSchWires[cellType, side];
form.ary[side].busLo ← GetBus
[CoreRoute.OrderedAtomicSchWires[cellType, side, , min ]];
form.ary[side].busHi ← GetBus
[CoreRoute.OrderedAtomicSchWires[cellType, side, max, ]];
form.ary[side].pins ← CoreRoute.FilteredInstanceLayoutPins[subInst, side];
form.ary[side].pins ← CoreRoute.FilterPins[form.ary[side].pins, wires, globals];
IF form.ary[side].bus#NIL THEN {
rw ← NARROW [CoreProperties.GetWireProp[form.ary[side].bus, wireWidthProp]];
form.ary[side].busSize ← IF rw=NIL THEN L4 ELSE rw^*lambda};
ENDLOOP;
form.vert ← CoreRoute.GetCellTypePropLayer[cellType, $VerticalMetal].layer;
Compute min, max, busMin and busMax
FOR side: Side IN Side DO
VertLayer: PROC[sideLayer: CD.Layer] RETURNS[vertLayer: CD.Layer] =
{RETURN[IF side=top OR side=bottom THEN sideLayer ELSE Other[sideLayer]]};
form.ary[side].min ← 0;
IF side=top OR side=bottom
THEN form.ary[side].max  ← subSize.x
ELSE form.ary[side].max  ← subSize.y;
IF form.ary[side].busLo
THEN form.ary[side].busMin ← L4;
IF form.ary[side].busHi THEN {IF side=top OR side=bottom
THEN form.ary[side].busMax ← subSize.x - L4
ELSE  form.ary[side].busMax ← subSize.y - L4};
AdjustPins345[form.ary[side].pins]; -- 3, 4, 5 => 4 lambda
FOR pins: WirePins ← form.ary[side].pins, pins.rest WHILE pins#NIL DO
pin:   WirePin ← pins.first;
sideLayer: CD.Layer ← Other[pin.layer]; 
IF form.vert#CD.commentLayer AND form.vert#VertLayer[sideLayer] THEN ERROR;
form.vert ← VertLayer[sideLayer];
IF pin.wire=form.ary[side].bus
THEN {
form.ary[side].busMin ← MIN[form.ary[side].busMin, pin.min];
form.ary[side].busMax ← MAX[form.ary[side].busMax, pin.max]}
ELSE {
IF form.ary[side].busLo THEN form.ary[side].busMin ←
MIN[form.ary[side].busMin, pin.min - L4 - form.ary[side].busSize];
IF form.ary[side].busHi THEN form.ary[side].busMax ←
MAX[form.ary[side].busMax, pin.max + L4 + form.ary[side].busSize]};
ENDLOOP;
form.ary[side].min ← MIN[form.ary[side].min, form.ary[side].busMin];
form.ary[side].max ← MAX[form.ary[side].max, form.ary[side].busMax];
ENDLOOP;
Check for conflicts in corner
IF
form.ary[left].busMax > subSize.y AND form.ary[top].busMin  < 0   OR
form.ary[right].busMax > subSize.y AND form.ary[top].busMax  > subSize.x OR
form.ary[right].busMin < 0   AND form.ary[bottom].busMax > subSize.x OR
form.ary[left].busMin < 0   AND form.ary[bottom].busMin < 0 THEN ERROR;
Two adjacent sides are both trying to extend into a corner.
If this was a little smarter, it could do a fancy corner for = bus wires.
Compute side widths
form.ary[left].width  ← MIN[form.ary[top].busMin, form.ary[bottom].busMin,0];
form.ary[bottom].width ← MIN[form.ary[left].busMin, form.ary[right].busMin,0];
form.ary[right].width ← MAX[form.ary[top].busMax, form.ary[bottom].busMax,0] - subSize.x;
form.ary[top].width  ← MAX[form.ary[left].busMax, form.ary[right].busMax,0] - subSize.y;
form.ary[right].width ← MAX[form.ary[right].width, 0];
form.ary[top].width  ← MAX[form.ary[top].width, 0];
FOR side: Side IN Side DO
minHeight: INTIF form.ary[side].bus=NIL
THEN 3*L4
ELSE 4*L4 + form.ary[side].busSize;
form.ary[side].width ← MAX[form.ary[side].width+L4, minHeight] ENDLOOP;
CoreRoute.FlushSchPinCache[subInst.type];
CoreRoute.FlushLayPinCache[subInst.type];
CoreProperties.PutCellTypeProp[cellType, changeLayersFormProp, form]};
Layout:  PWCore.LayoutProc  = {
name:  IO.ROPE     ← CoreOps.GetCellTypeName[cellType];
data:  CoreClasses.RecordCellType ← NARROW[cellType.data];
form:  ChangeLayersForm ← NARROW[
CoreProperties.GetCellTypeProp[cellType, changeLayersFormProp]];
subObj: CD.Object    ← PWCore.Layout[data[0].type];
subSize: CD.Position   ← CD.InterestSize[subObj];
cdInstances: CD.InstanceList ← LIST [CDInstances.NewInst[
ob: subObj, trans: [CDBasics.NegOffset[CD.InterestBase[subObj]]] ]];
Build routing objects.
FOR side: Side IN Side DO
nodes:  SymTab.Ref ← SymTab.Create[];
width: INT ← form.ary[side].width;
min:  INT ← form.ary[side].min;
max:  INT ← form.ary[side].max;
AddRect: PROC
[wire: Core.Wire, size: CD.Position, lay: CD.Layer, off, min: INT] = {
rect: CD.Object;
IF side=top OR side=bottom THEN size ← [size.y, size.x];
rect ← CDRects.CreateRect[size, lay];
AddPositionedObject[wire, rect, off, min]};
AddVias: PROC
[wire: Core.Wire, size: CD.Position, off, min: INT] = {
vias: CD.Object ← IF side=top OR side=bottom
THEN Vias[size.y, size.x]
ELSE Vias[size.x, size.y];
AddPositionedObject[wire, vias, off, min]};
AddPositionedObject: PROC[wire: Core.Wire, obj: CD.Object, off, min: INT] = {
label: Route.Label ← CoreRoute.LabelInternal[data.internal, wire];
pos: REF LIST OF CDRoutingObjects.PlacedObject ←
NARROW[SymTab.Fetch[nodes, label].val];
szX: INTCD.InterestSize[obj].x;
szY: INTCD.InterestSize[obj].y;
po: CDRoutingObjects.PlacedObject ← SELECT side FROM
top  => [obj, [min,    off    ]],
bottom => [obj, [min,    width-off-szY ]],
right  => [obj, [off,     min    ]],
left  => [obj, [width-off-szX, min    ]] ENDCASE=>ERROR;
IF pos=NIL THEN {
pos ← NEW[LIST OF CDRoutingObjects.PlacedObject ← NIL];
[]←SymTab.Store[nodes, label, pos]};
pos^ ← CONS[po, pos^]};
routingIR: CD.Rect ← SELECT side FROM
left  => [0, min, width, max],
right  => [0, min, width, max],
top  => [min, 0, max, width],
bottom => [min, 0, max, width],
ENDCASE => ERROR;
routingPos: CD.Position ← SELECT side FROM
left  => [-width,  0],
right  => [subSize.x, 0],
top  => [0,   subSize.y],
bottom => [0,   -width],
ENDCASE => ERROR;
dstLay: CD.Layer ← IF side=top OR side=bottom THEN form.vert ELSE Other[form.vert];
srcLay: CD.Layer ← Other[dstLay];
IF form.ary[side].pins=NIL THEN LOOP;
FOR pins: WirePins ← form.ary[side].pins, pins.rest WHILE pins#NIL DO
pin:  WirePin ← pins.first;
size:  INT  ← pin.max - pin.min;
IF pin.wire=form.ary[side].bus
THEN
AddRect[pin.wire, [3*L4,  size], srcLay, 0,  pin.min]
ELSE {
AddRect[pin.wire, [2*L4,  size], srcLay, 0,  pin.min];
AddVias[pin.wire, [L4,   size],    L4, pin.min];
AddRect[pin.wire, [width-L4, size], dstLay, L4, pin.min]};
ENDLOOP;
IF form.ary[side].busLo THEN {
size: INT ← form.ary[side].busSize;
loc: INT ← form.ary[side].busMin;
AddRect[form.ary[side].bus, [size+L4, size], dstLay, 3*L4, loc];
AddVias[form.ary[side].bus, [size,  size],      3*L4, loc]};
IF form.ary[side].busHi THEN {
size: INT ← form.ary[side].busSize;
loc: INT ← form.ary[side].busMax-size;
AddRect[form.ary[side].bus, [size+L4, size], dstLay, 3*L4, loc];
AddVias[form.ary[side].bus, [size,  size],      3*L4, loc]};
IF form.ary[side].bus#NIL THEN {
size: CD.Position ←
[form.ary[side].busSize, form.ary[side].busMax-form.ary[side].busMin];
AddRect[form.ary[side].bus, size, srcLay, 3*L4, form.ary[side].busMin]};
cdInstances ← CONS [
CDInstances.NewInst[
ob: CDRoutingObjects.CreateRoutingObject[
nodes: CDRoutingObjects.CreateNodes[nodes],
ir:  routingIR],
trans: [routingPos]],
cdInstances];
ENDLOOP;
obj ← PW.CreateCell[instances: cdInstances, name: name.Cat[".mask"] ]};
Decorate: PWCore.DecorateProc = {
WireToLabels: PROC [wire: Core.Wire] RETURNS [labels: LIST OF Route.Label ← NIL] =
{RETURN[LIST [CoreRoute.LabelInternal[data.internal, wire]]]};
data: CoreClasses.RecordCellType ← NARROW [cellType.data];
CoreRoute.DecorateRoutedArea[cellType: cellType, obj: obj, wireToLabels: WireToLabels]};
Auxillary procedures
Adjust345: PROC[min, max: INT] RETURNS[minn, maxx: INT] = {
minn ← min; maxx ← max;
IF max-min IN (0..5*lambda] THEN {
minn ← (min+max)/2 - 2*lambda;
maxx ← (min+max)/2 + 2*lambda} };
AdjustPins345: PROC[pins: WirePins] = {
FOR pins ← pins, pins.rest WHILE pins#NIL DO
[pins.first.min, pins.first.max] ← Adjust345[pins.first.min, pins.first.max] ENDLOOP};
Other: PROC[lay: CD.Layer] RETURNS[CD.Layer] =
{RETURN[IF lay=CMosB.met THEN CMosB.met2 ELSE CMosB.met]};
Vias: PROC[sizex, sizey: INT] RETURNS[obj: CD.Object] = {RETURN[
CDSimpleRules.LargeContact[$cmosB, NIL, [sizex, sizey], CMosB.met, CMosB.met2]]};
Vias: PROC[sizex, sizey: INT] RETURNS[obj: CD.Object] = {
Bias:  PROC[s: INT] RETURNS[bias:INT] = {RETURN[(s+d-((s+d)/(3*d))*3*d)/2]};
node:  IO.ROPE   ← "node";
insts:  CD.InstanceList ← NIL;
name:  IO.ROPE   ← IO.PutFR["Vias%gx%gy", IO.int[sizex], IO.int[sizey]];
via:  CD.Object  ← CDSimpleRules.Contact[technologyKey, CMosB.met, CMosB.met2];
d:   INT   ← L4/2;
FOR x: INT ← Bias[sizex], x + 3*d WHILE x <= sizex-(2*d) DO
FOR y: INT ← Bias[sizey], y + 3*d WHILE y <= sizey-(2*d) DO
insts ← CONS[NEW[CD.InstanceRep ← [via, [[x, y]]]], insts];
CDProperties.PutProp[insts.first, $SignalName, node] ENDLOOP ENDLOOP;
IF insts=NIL THEN ERROR;
insts ← CONS[NEW[CD.InstanceRep ← [CDRects.CreateRect[[sizex, sizey], CMosB.met]]], insts];
CDProperties.PutProp[insts.first, $SignalName, node];
insts ← CONS[NEW[CD.InstanceRep ← [CDRects.CreateRect[[sizex, sizey], CMosB.met2]]],insts];
CDProperties.PutProp[insts.first, $SignalName, node];
obj ← PW.CreateCell[instances: insts, name: Rope.Cat["Adj.mask"], ir: [0, 0, sizex, sizey]]};
AddTo: PROC[side: Side, wire: Core.Wire, obj: CD.Object, off, min: INT, core: CD.Position, fullName: IO.ROPE, insts: CD.InstanceList] RETURNS[CD.InstanceList] = {
inst: CD.Instance ← NEW[CD.InstanceRep ← [obj]];
len: INTCD.InterestSize[obj].x;
wid: INTCD.InterestSize[obj].y;
inst.trans ← SELECT side FROM
top  => [[min+wid,   off+core.y ], rotate90],
bottom => [[min+wid,  -off-len  ], rotate90],
right  => [[ off+core.x,  min   ], original],
left  => [[-off-len,  min   ], original] ENDCASE=>ERROR;
CoreGeometry.AddPins[layDeco, wire, LIST[CoreGeometry.Instance[inst.ob, inst.trans]]];
CDProperties.PutProp[inst, $SignalName, fullName];
insts ← CONS[inst, insts];
RETURN[insts]};
Register layout atoms
[] ← PWCore.RegisterLayoutAtom[changeLayersLayoutProp,  Layout, Decorate, Attribute];
[] ← PWCore.RegisterLayoutAtom[changeLayersLayoutRawProp, Layout, Decorate];
END.