Attribute: PWCore.AttributesProc = {
SchSideWires:
PROC[side: Side, min:
INT ←
FIRST[
INT], max:
INT ←
LAST[
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: INT ← IF 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: INT ← GetSideExtention[cellType, side];
strangeLayerFound: BOOL ← FALSE;
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: INT ← GetSideExtention[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: 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^]};
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"] ]};