CoreRouteExtend.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Don Curry August 25, 1988 4:52:28 pm PDT
DIRECTORY
CD, CDBasics, CDInstances, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, Core, CoreClasses, CoreCreate, CoreGeometry, CoreOps, CoreProperties, CoreRoute, IO, PW, PWCore, Rope, Route, Sisyph, SymTab, TerminalIO;
CoreRouteExtend: CEDAR PROGRAM
IMPORTS
CD, CDBasics, CDInstances, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, CoreGeometry, CoreOps, CoreProperties, CoreRoute, IO, PW, PWCore, Rope, Sisyph, SymTab, TerminalIO =
BEGIN
Types and constants
ExtendForm:    TYPE = REF ExtendFormAry;
ExtendFormAry:   TYPE = RECORD[
vert:   CD.Layer ← CD.commentLayer,
sameLayers: BOOL  ← TRUE,
ary:   ARRAY Side OF ExtendFormRec ];
ExtendFormRec:   TYPE = RECORD[
pins:  WirePins  ← NIL,
min:  INT   ← LAST[INT],
max:  INT   ← FIRST[INT],
width: INT   ← 0,
wires:  Wires   ← NIL,
buses:  Wires   ← NIL,
busLo: Wires   ← NIL,
busHi: Wires   ← NIL];
BusRec:      TYPE = RECORD[
loc:  INT   ← 0,
width: INT   ← 0,
min:  INT   ← LAST[INT],
max:  INT   ← FIRST[INT]];
Wires:       TYPE = Core.Wires;
WirePin:       TYPE = CoreRoute.WirePin;
WirePins:      TYPE = CoreRoute.WirePins;
Side:       TYPE = CoreGeometry.Side;
extendFormProp:    ATOM = $ExtendForm;
verticalMetalProp:   ATOM = $VerticalMetal;
changeLayersProp:   ATOM = $ChangeLayers;
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;
sideProp: ARRAY Side OF ATOM ← [bottom: $Bottom, top: $Top, left: $Left, right: $Right];
sizeProp: ARRAY Side OF ATOM ← [bottom: $SizeY, top: $SizeY, left: $SizeX, right: $SizeX];
Attribute, Layout and Decorate Procs
Attribute: PWCore.AttributesProc = {
SchSideWires: PROC[side: Side, min: INTFIRST[INT], max: INTLAST[INT]]
RETURNS [wires: Core.Wires] =
{RETURN[CoreRoute.OrderedAtomicSchWires[cellType, side, min, max]]};
AddTopOrBottomEnds: PROC[topBot, ltRt: Side] = {
buses: Wires ← IF topBot=top
THEN form.ary[ltRt].busHi
ELSE form.ary[ltRt].busLo;
IF form.ary[topBot].width=0 THEN RETURN;
FOR buses ← buses, buses.rest WHILE buses#NIL DO
rec: REF BusRec ← EnsureBusSideRec[buses.first, ltRt];
loc: INTIF ltRt=left THEN 0 - rec.width - rec.loc ELSE subSize.x + rec.loc;
pin: WirePin ← [buses.first, loc, loc+rec.width, form.vert];
form.ary[topBot].pins ← CONS[pin, form.ary[topBot].pins];
ENDLOOP};
data:  CoreClasses.RecordCellType ← NARROW[cellType.data];
name:  IO.ROPE       ← CoreOps.GetCellTypeName[cellType];
form:  ExtendForm ← NEW[ExtendFormAry ←[vert:CD.commentLayer]];
subInst: CoreCreate.CellInstance   ← data[0];
subObj: CD.Object  ← PWCore.Layout[subInst.type];
subSize: CD.Position ← CD.InterestSize[subObj];
globals: Wires   ← CoreRoute.GlobalWires[cellType];
pIR:  CD.Rect  ← CD.InterestRect[CoreGeometry.GetObject[schDeco, cellType]];
cIR:  CD.Rect  ← CoreRoute.SchMappedIR[subInst];
form.ary[left].busLo  ← SchSideWires[bottom, ,  cIR.x1-pIR.x1 ];
form.ary[left].busHi  ← SchSideWires[top,  ,  cIR.x1-pIR.x1 ];
form.ary[right].busLo ← SchSideWires[bottom,  cIR.x2-pIR.x1, ];
form.ary[right].busHi ← SchSideWires[top,   cIR.x2-pIR.x1, ];
form.ary[bottom].busLo ← SchSideWires[left, ,  cIR.y1-pIR.y1 ];
form.ary[bottom].busHi ← SchSideWires[right, ,  cIR.y1-pIR.y1 ];
form.ary[top].busLo  ← SchSideWires[left,  cIR.y2-pIR.y1, ];
form.ary[top].busHi  ← SchSideWires[right,  cIR.y2-pIR.y1, ];
form.vert     ← CoreRoute.GetCellTypePropLayer[cellType, verticalMetalProp].layer;
form.sameLayers   ← CoreProperties.GetCellTypeProp[cellType, changeLayersProp]=NIL;
FOR side: Side IN Side DO
min:  INT  ← IF LeftRight[side]  THEN cIR.y1-pIR.y1 ELSE cIR.x1-pIR.x1;
max:  INT  ← IF LeftRight[side]  THEN cIR.y2-pIR.y1 ELSE cIR.x2-pIR.x1;
wires:  Wires  ← CoreRoute.OrderedAtomicSchWires[cellType, side, min, max];
form.ary[side].wires ← wires;
form.ary[side].buses ← MergeOrderedWires[form.ary[side].busLo, form.ary[side].busHi];
FOR buses: Wires ← form.ary[side].buses, buses.rest WHILE buses#NIL DO
rec: REF BusRec ← EnsureBusSideRec[buses.first, side];
wires ← CONS[buses.first, wires] ENDLOOP;
form.ary[side].pins ← CoreRoute.FilteredInstanceLayoutPins[subInst, side];
form.ary[side].pins ← CoreRoute.FilterPins[form.ary[side].pins, wires, globals];
IF ~form.sameLayers AND
form.ary[side].buses#NIL AND
form.ary[side].buses.rest#NIL THEN ERROR;
can't do changelayers with more than one bus
ENDLOOP;
Compute busWidths and VertLayer
FOR side: Side IN Side DO
VertLayer: PROC[sideLayer: CD.Layer] RETURNS[vertLayer: CD.Layer] = {RETURN
[IF LeftRight[side] # form.sameLayers THEN sideLayer ELSE OtherLayer[sideLayer]]};
w:  INTGetSideExtention[cellType, side];
strangeLayerFound: BOOLFALSE;
IF w=0 AND form.sameLayers THEN LOOP;
IF ~form.sameLayers THEN 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  ← pin.layer; 
busRec:  REF BusRec ← ExistingBusSideRec[pin.wire, side];
IF NOT MetLayer[sideLayer]
THEN {
IF NOT strangeLayerFound THEN
TerminalIO.PutF["*** %g side of %g has strange pin layer.\n",
IO.rope[SideNm[side]], IO.rope[CoreOps.GetCellTypeName[cellType]]];
strangeLayerFound ← TRUE}
ELSE {
IF form.vert=CD.commentLayer OR form.vert=VertLayer[sideLayer]
THEN form.vert ← VertLayer[sideLayer]
ELSE TerminalIO.PutF["*** %g side of %g has inconsistent pin layer.\n",
IO.rope[SideNm[side]], IO.rope[CoreOps.GetCellTypeName[cellType]]];
IF busRec#NIL THEN busRec.width ← MAX[busRec.width, pin.max-pin.min]};
ENDLOOP ENDLOOP;
IF NOT MetLayer[form.vert] THEN ERROR;
Override bus width if wire has wireWidthProp
FOR side: Side IN Side DO
FOR buses: Wires ← form.ary[side].buses, buses.rest WHILE buses#NIL DO
w:  REF INT  ← NARROW[CoreProperties.GetWireProp[buses.first, wireWidthProp]];
rec: REF BusRec ← EnsureBusSideRec[buses.first, side];
rec.width ← IF w#NIL THEN w^*lambda ELSE 4*lambda ENDLOOP ENDLOOP;
Compute side widths and bus locs
FOR side: Side IN Side DO
w:  INTGetSideExtention[cellType, side];
buses: Wires ← form.ary[side].buses;
IF side=left OR side=bottom THEN buses ← CoreOps.Reverse[buses];
form.ary[side].width ← IF ~form.sameLayers
THEN 3*L4 ELSE IF form.ary[side].buses=NIL THEN 0 ELSE L4;
FOR buses ← buses, buses.rest WHILE buses#NIL DO
rec: REF BusRec ← EnsureBusSideRec[buses.first, side];
rec.loc ← form.ary[side].width;
form.ary[side].width ← form.ary[side].width + rec.width + L4 ENDLOOP;
IF w#0 THEN {
size: INT ← w*lambda;
IF size < form.ary[side].width
THEN TerminalIO.PutF["*** Warning: %g side Extend of %g
Needs %g but was specified as %g.",
IO.rope[SideNm[side]],
IO.rope[name],
IO.int[form.ary[side].width/lambda],
IO.int[w]]
ELSE form.ary[side].width←size};
form.ary[side].min ← 0;
form.ary[side].max ← IF LeftRight[side] THEN subSize.y ELSE subSize.x;
ENDLOOP;
Extend top and bottom routing cells
IF form.ary[top].width#0  THEN {
form.ary[top].min   ← form.ary[top].min  - form.ary[left].width;
form.ary[top].max   ← form.ary[top].max  + form.ary[right].width};
IF form.ary[bottom].width#0  THEN {
form.ary[bottom].min  ← form.ary[bottom].min - form.ary[left].width;
form.ary[bottom].max  ← form.ary[bottom].max + form.ary[right].width};
Add Top and Bottom Ends
AddTopOrBottomEnds[top,  left];
AddTopOrBottomEnds[top,  right];
AddTopOrBottomEnds[bottom, left];
AddTopOrBottomEnds[bottom, right];
Compute busMins, busMaxs
FOR side: Side IN Side DO
IF form.ary[side].width=0 THEN LOOP;
FOR pins: WirePins ← form.ary[side].pins, pins.rest WHILE pins#NIL DO
pin:   WirePin  ← pins.first;
busRec:  REF BusRec ← ExistingBusSideRec[pin.wire, side];
IF NOT MetLayer[pin.layer] THEN LOOP;
IF busRec#NIL THEN {
busRec.min  ← MIN[busRec.min,  pin.min];
busRec.max  ← MAX[busRec.max,  pin.max]} ENDLOOP ENDLOOP;
Extend buses to ends of routing cells
FOR side: Side IN Side DO
FOR buses: Wires ← form.ary[side].busLo, buses.rest WHILE buses#NIL DO
EnsureBusSideRec[buses.first, side].min ← form.ary[side].min ENDLOOP;
FOR buses: Wires ← form.ary[side].busHi, buses.rest WHILE buses#NIL DO
EnsureBusSideRec[buses.first, side].max ← form.ary[side].max ENDLOOP ENDLOOP;
CoreRoute.FlushSchPinCache[subInst.type];
CoreRoute.FlushLayPinCache[subInst.type];
CoreProperties.PutCellTypeProp[cellType, extendFormProp, form];
ShowExtendForm[cellType]};
Layout:  PWCore.LayoutProc  = {
name:  IO.ROPE     ← CoreOps.GetCellTypeName[cellType];
data:  CoreClasses.RecordCellType ← NARROW[cellType.data];
form:  ExtendForm ← NARROW[
CoreProperties.GetCellTypeProp[cellType, extendFormProp]];
resultIR: CD.Rect;
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
AddRect: PROC
[wire: Core.Wire, size: CD.Position, lay: CD.Layer, off, min: INT] = {
rect: CD.Object;
IF ~LeftRight[side] 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 LeftRight[side]
THEN Vias[size.x, size.y]
ELSE Vias[size.y, size.x];
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^]};
nodes:  SymTab.Ref ← SymTab.Create[];
width: INT ← form.ary[side].width;
fMin:  INT ← form.ary[side].min;
fMax:  INT ← form.ary[side].max;
routingIR: CD.Rect ← SELECT side FROM
left  => [0, fMin, width, fMax],
right  => [0, fMin, width, fMax],
top  => [fMin, 0, fMax, width],
bottom => [fMin, 0, fMax, 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;
trunk:  CD.Layer ← IF LeftRight[side] THEN form.vert ELSE OtherLayer[form.vert];
branch: CD.Layer ← OtherLayer[trunk];
srcLay: CD.Layer ← IF form.sameLayers THEN branch ELSE trunk;
oneBus: BOOL  ← NOT form.sameLayers; -- later we can count
SELECT side FROM
left  => resultIR.x1 ← routingPos.x;
right  => resultIR.x2 ← routingPos.x + width;
top  => resultIR.y2 ← routingPos.y + width;
bottom => resultIR.y1 ← routingPos.y;
ENDCASE => ERROR;
IF width=0 OR 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;
busRec: REF BusRec ← ExistingBusSideRec[pin.wire, side];
corner: BOOL   ← ~LeftRight[side] AND (pin.min < 0 OR pin.max > subSize.x);
extend: BOOL   ← CoreOps.Member[form.ary[side].wires, pin.wire];
IF NOT MetLayer[pin.layer] THEN LOOP;
IF corner
THEN {
AddRect[pin.wire, [width, size], branch, 0,    pin.min];
IF busRec#NIL THEN AddVias[pin.wire,[busRec.width, size], busRec.loc, pin.min]}
ELSE IF busRec=NIL
THEN SELECT TRUE FROM
pin.layer=branch =>
AddRect[pin.wire, [width,  size], pin.layer, 0,  pin.min];
NOT form.sameLayers => {
AddRect[pin.wire, [2*L4,  size], pin.layer, 0,  pin.min];
AddVias[pin.wire, [L4,   size],    L4, pin.min];
AddRect[pin.wire, [width-L4, size], branch, L4, pin.min]};
ENDCASE -- skip pin
ELSE IF oneBus OR pin.layer=branch THEN {
AddRect[pin.wire, [busRec.loc,    size], pin.layer,  0, pin.min];
IF pin.layer#trunk OR extend THEN
AddVias[pin.wire, [busRec.width,   size],   busRec.loc, pin.min];
IF extend THEN
AddRect[pin.wire, [width - busRec.loc, size], branch, busRec.loc, pin.min]};
ENDLOOP;
Add Trunks
FOR buses: Wires ← form.ary[side].buses, buses.rest WHILE buses#NIL DO
rec: REF BusRec ← EnsureBusSideRec[buses.first, side];
size: CD.Position ← [rec.width, rec.max-rec.min];
AddRect[buses.first, size, trunk, rec.loc, rec.min] ENDLOOP;
cdInstances ← CONS [
CDInstances.NewInst[
ob: CDRoutingObjects.CreateRoutingObject[
nodes: CDRoutingObjects.CreateNodes[nodes],
ir:  routingIR],
trans: [routingPos]],
cdInstances];
ENDLOOP;
obj ← PW.CreateCell[instances: cdInstances, ir: resultIR, 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
EnsureBusSideRec: PROC[wire: Core.Wire, side: Side] RETURNS[busRec: REF BusRec] = {
busRec ← ExistingBusSideRec[wire, side];
IF busRec=NIL THEN {
busRec ← NEW[BusRec ← [0, 0, LAST[INT], FIRST[INT]]];
[]𡤌oreProperties.PutWireProp[wire, sideProp[side], busRec]}};
ExistingBusSideRec: PROC[wire: Core.Wire, side: Side] RETURNS[busRec: REF BusRec] =
{RETURN[NARROW[CoreProperties.GetWireProp[wire, sideProp[side]]]]};
GetSideExtention: PROC[cellType: Core.CellType, side: Side] RETURNS[extention: INT] = {
LoSize: PROC[dif: INT] RETURNS[INT] = {RETURN[dif/2]};
HiSize: PROC[dif: INT] RETURNS[INT] = {RETURN[dif - LoSize[dif]]};
data:  CoreClasses.RecordCellType ← NARROW[cellType.data];
inSize: CD.Position ← CD.InterestSize[PWCore.Layout[data[0].type]];
sizeProp: ATOM  ← SELECT side FROM left, right => $XSize, ENDCASE => $YSize;
sizeRef: REF INT ← NARROW[CoreProperties.GetCellTypeProp[cellType, sizeProp]];
sideRef: REF INT ← NARROW[CoreProperties.GetCellTypeProp[cellType, sideProp[side]]];
extention ← IF sideRef#NIL
THEN sideRef^
ELSEIF sizeRef=NIL
THEN 0
ELSESELECT side FROM
left  => LoSize[MAX[0, sizeRef^ - inSize.x/lambda]],
right  => HiSize[MAX[0, sizeRef^ - inSize.x/lambda]],
top  => HiSize[MAX[0, sizeRef^ - inSize.y/lambda]],
bottom => LoSize[MAX[0, sizeRef^ - inSize.y/lambda]],
ENDCASE => ERROR};
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};
LeftRight:   PROC[side: Side]      RETURNS[leftRight: BOOL] =
{RETURN[side=left OR side=right]};
MergeOrderedWires: PROC[a, b: Core.Wires] RETURNS[merge: Core.Wires] = {
DO
SELECT TRUE FROM
a=NIL AND b=NIL   => EXIT;
a=NIL       => {merge←CONS[b.first, merge];    b𡤋.rest};
b=NIL       => {merge←CONS[a.first, merge]; a𡤊.rest};
a.first=b.first     => {merge←CONS[a.first, merge]; a𡤊.rest; b𡤋.rest};
CoreOps.Member[b, a.first] => {merge←CONS[b.first, merge];    b𡤋.rest};
ENDCASE      => {merge←CONS[a.first, merge]; a𡤊.rest};
ENDLOOP;
RETURN[CoreOps.Reverse[merge]]};
OtherLayer:  PROC[lay: CD.Layer]    RETURNS[CD.Layer] =
{RETURN[IF lay=CMosB.met THEN CMosB.met2 ELSE CMosB.met]};
MetLayer: PROC[layer: CD.Layer] RETURNS[isMetal1or2: BOOL] =
{RETURN[layer=CMosB.met OR layer=CMosB.met2]};
ShowExtendForm: PROC[cellType: Core.CellType] = {
name: IO.ROPE  ← CoreOps.GetCellTypeName[cellType];
form: ExtendForm ← NARROW[CoreProperties.GetCellTypeProp[cellType, extendFormProp]];
tos: IO.STREAM ← TerminalIO.TOS[];
tos.PutF["Extend Layout: %g\n", IO.rope[name] ];
tos.PutF[" Left:  %g\n", IO.int[form.ary[left].width]];
tos.PutF[" Right: %g\n", IO.int[form.ary[right].width]];
tos.PutF[" Top:  %g\n", IO.int[form.ary[top].width]];
tos.PutF[" Bottom: %g\n", IO.int[form.ary[bottom].width]]};
SideNm: ARRAY Side OF IO.ROPE
[bottom: "Bottom",  top: "Top",  left: "Left",  right: "Right"];
viaTab: SymTab.Ref ← SymTab.Create[];
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;
obj ← NARROW[SymTab.Fetch[viaTab, name].val];
IF obj#NIL THEN RETURN[obj];
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: name, ir: [0, 0, sizex, sizey]];
[]←SymTab.Store[viaTab, name, obj]};
Register layout atoms
[] ← PWCore.RegisterLayoutAtom[$ExtendX,  Layout, Decorate, Attribute];
END.