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:
BOOL ←
TRUE] = {
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:
INT ←
IF 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: INT ← CD.InterestSize[obj].x;
szY: INT ← CD.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"] ]};