StackAttributes: PWCore.AttributesProc = {
IRCord:
PROC[ir:
CD.Rect]
RETURNS[first, last, min, max:
INT] = {
IF form.inX
THEN RETURN[ first: ir.x1, last: ir.x2, min: ir.y1, max: ir.y2]
ELSE RETURN[ first: ir.y1, last: ir.y2, min: ir.x1, max: ir.x2] };
CellLaySize:
PROC[ct: CellType]
RETURNS[laySize: LaySize] = {
first, last, min, max: INT;
[first, last, min, max] ← IRCord[CD.InterestRect[PWCore.Layout[ct]]];
RETURN[[width: max-min, height: last-first]]};
BLayerUnKnown:
PROC
RETURNS[
BOOL] =
{RETURN[form.branchLayer=CD.commentLayer]};
data: CoreClasses.RecordCellType ← NARROW[cellType.data];
form: StackForm ← NEW[StackFormRec ← [inX: SchSort[cellType]]];
irFirst: INT ← IRCord[CD.InterestRect[CoreGeometry.GetObject[schDeco, cellType]]].first;
irLast: INT ← IRCord[CD.InterestRect[CoreGeometry.GetObject[schDeco, cellType]]].last;
loPos: INT ← 0;
hiPos: INT ← 0;
index: INT ← 0;
sections: LIST OF StackSection ← NIL;
previous: LIST OF StackSection ← NIL;
lastSection: LIST OF StackSection ← NIL;
globals: Core.Wires ← CoreRoute.GlobalWires[cellType];
firstWires: Core.Wires ← CoreRoute.OrderedAtomicSchWires[cellType, RSide[form.inX, first]];
lastWires: Core.Wires ← CoreRoute.OrderedAtomicSchWires[cellType, RSide[form.inX, last]];
form.justification ← GetJustification[cellType];
Build first cut at section list. Add channels where gaps between subcells exist.
FOR index ← 0, index+1
DO
minWires, maxWires: Core.Wires ← NIL;
abut: StackAbutRec;
loPos ← hiPos;
hiPos ←
IF index = data.size
THEN irLast-irFirst ELSE IRCord[CoreRoute.SchMappedIR[data[index]].ir].first - irFirst;
IF hiPos > loPos
THEN {
chan: REF StackChanRec ← NEW[StackChanRec ← []];
form.sec ← CONS[[chan: chan], form.sec];
chan.minPins ← SwitchBoxPins[ CoreRoute.OrderedAtomicSchWires
[cellType, RSide[form.inX, min], loPos, hiPos]];
chan.maxPins ← SwitchBoxPins[ CoreRoute.OrderedAtomicSchWires
[cellType, RSide[form.inX, max], loPos, hiPos]]};
IF index = data.size THEN EXIT;
IF form.sec=
NIL
OR form.sec.first.chan#
NIL
THEN
-- need new abut section
{form.sec ← CONS[[abuts: NIL], form.sec]};
abut ← [
inst: index,
firstPins: CoreRoute.FilteredInstanceLayoutPins[data[index], RSide[form.inX, first]],
lastPins: CoreRoute.FilteredInstanceLayoutPins[data[index], RSide[form.inX, last]],
minPins: CoreRoute.FilteredInstanceLayoutPins[data[index], RSide[form.inX, min]],
maxPins: CoreRoute.FilteredInstanceLayoutPins[data[index], RSide[form.inX, max]],
laySize: CellLaySize[data[index].type] ];
loPos ← hiPos;
hiPos ← IRCord[CoreRoute.SchMappedIR[data[index]].ir].last - irFirst;
minWires ← CoreRoute.OrderedAtomicSchWires[cellType, RSide[form.inX, min], loPos, hiPos];
maxWires ← CoreRoute.OrderedAtomicSchWires[cellType, RSide[form.inX, max], loPos, hiPos];
abut.minPins ← FilterPins[abut.minPins, minWires, globals];
abut.maxPins ← FilterPins[abut.maxPins, maxWires, globals];
form.sec.first.abuts ← CONS[abut, form.sec.first.abuts] ENDLOOP;
Reverse lists.
form.sec ← ReverseSections[form.sec];
FOR sections ← form.sec, sections.rest
WHILE sections#
NIL
DO
sections.first.abuts ← ReverseAbuts[sections.first.abuts] ENDLOOP;
Insert channel sections between incompatible abuts.
IF CoreProperties.GetCellTypeProp[cellType, $TrustMe]=
NIL
THEN
FOR sections ← form.sec, sections.rest
WHILE sections#
NIL
DO
abuts: LIST OF StackAbutRec ← sections.first.abuts;
FOR abuts ← abuts, abuts.rest
WHILE abuts#
NIL
AND abuts.rest#
NIL
DO
IF CheckInterface[data, form.inX, abuts.first.inst, abuts.rest.first.inst ] THEN LOOP;
sections.rest ← CONS[[abuts: abuts.rest], sections.rest];
sections.rest ← CONS[[chan: NEW[StackChanRec ← []]], sections.rest];
abuts.rest ← NIL;
ENDLOOP ENDLOOP;
Compute the min/max for each abut section as well as the overall min/max or max (width).
previous ← NIL;
FOR sections ← form.sec, sections.rest
WHILE sections#
NIL
DO
abuts: LIST OF StackAbutRec ← sections.first.abuts;
IF abuts#
NIL
THEN {
sections.first.abutMin ← abuts.first.off;
sections.first.abutMax ← abuts.first.off + abuts.first.laySize.width;
FOR abuts ← abuts, abuts.rest
WHILE abuts#
NIL
AND abuts.rest#
NIL
DO
index: INT ← abuts.first.inst;
thisWidth: INT ← abuts.first.laySize.width;
nextWidth: INT ← abuts.rest.first.laySize.width;
offset:
INT ←
IF abuts.rest.first.firstPins#
NIL
THEN abuts.first.lastPins.first.min - abuts.rest.first.firstPins.first.min
ELSE
SELECT form.justification
FROM
bottomLeft => 0,
topRight => (thisWidth - nextWidth),
ENDCASE => 0; -- really should be two sections with null channel
loc: INT ← abuts.rest.first.off ← abuts.first.off + offset;
sections.first.abutMin ← MIN[loc, sections.first.abutMin];
sections.first.abutMax ← MAX[loc + nextWidth, sections.first.abutMax];
ENDLOOP;
IF form.justification = bestFit
THEN {
form.min ← MIN[form.min, sections.first.abutMin];
form.max ← MAX[form.max, sections.first.abutMax]}
ELSE {
form.min ← 0;
form.max ← MAX[form.max, sections.first.abutMax-sections.first.abutMin]} }
ELSE
IF form.justification=bestFit
AND sections.rest#
NIL
AND previous#
NIL
THEN {
FOR abuts ← previous.first.abuts, abuts.rest WHILE abuts.rest#NIL DO ENDLOOP;
sections.rest.first.abuts.first.off ← abuts.first.off + FindBestOffset
[abuts.first.lastPins, sections.rest.first.abuts.first.firstPins]};
previous ← sections ENDLOOP;
Propagate max (=maxWidth) or (if justify bestFit) min/max to sections.
Examine layouts of channel bounding subcells to discover routing layers.
IF BLayerUnKnown[]
THEN [form.branchLayer, form.trunkLayer] ←
GetCellTypePropLayer[cellType, branchLayerProp];
IF BLayerUnKnown[]
THEN [form.trunkLayer, form.branchLayer] ←
GetCellTypePropLayer[cellType, trunkLayerProp];
IF BLayerUnKnown[]
THEN
IF form.inX
THEN [form.trunkLayer, form.branchLayer] ←
GetCellTypePropLayer[cellType, verticalLayerProp]
ELSE [form.branchLayer, form.trunkLayer] ←
GetCellTypePropLayer[cellType, verticalLayerProp];
previous ← NIL;
FOR sections ← form.sec, sections.rest
WHILE sections#
NIL
DO
IF sections.first.abuts#
NIL
THEN
SELECT form.justification
FROM
bottomLeft => sections.first.abutMax ← sections.first.abutMin + form.max; -- width
topRight => sections.first.abutMin ← sections.first.abutMax - form.max; -- width
ENDCASE => {sections.first.abutMin𡤏orm.min; sections.first.abutMax𡤏orm.max}
ELSE {
Ck:
PROC[lay: CD.Layer] = {
IF lay#
CD.commentLayer
AND lay#form.branchLayer
THEN
TerminalIO.PutF["***Warning: Routing layers are incompatible.\n"]};
chan: REF StackChanRec ← sections.first.chan;
top: CD.Layer ←
IF sections.rest#
NIL
THEN GetRoutingLayer[sections.rest.first.abuts.first.firstPins]
ELSE CD.commentLayer;
bot: CD.Layer ←
IF previous#
NIL
THEN GetRoutingLayer[ReverseAbuts[previous.first.abuts].first.lastPins]
ELSE CD.commentLayer;
IF chan=NIL THEN ERROR;
sections.first.abutMin ← form.min; -- just clean up, not really needed
sections.first.abutMax ← form.max; -- just clean up, not really needed
IF BLayerUnKnown[] THEN form.branchLayer ← top ELSE Ck[top];
IF BLayerUnKnown[] THEN form.branchLayer ← bot ELSE Ck[bot]};
previous ← sections ENDLOOP;
IF BLayerUnKnown[]
THEN {
form.branchLayer ← IF form.inX THEN CMosB.met ELSE CMosB.met2;
TerminalIO.PutF["Warning: Unconstrained branchLayer. Defaulting to %g\n",
IO.rope[IF form.inX THEN "metal" ELSE "metal2"]] };
form.trunkLayer ← ResolveRoutingLayer [form.trunkLayer, form.branchLayer];
Initialize channel first and last WirePins;
FOR sections ← form.sec, sections.rest
WHILE sections#
NIL
DO
offset: INT;
pins: WirePins;
abuts: LIST OF StackAbutRec;
abut: StackAbutRec;
IF sections.first.chan=NIL THEN {lastSection ← sections; LOOP};
IF lastSection#
NIL
THEN {
FOR abuts ← lastSection.first.abuts, abuts.rest WHILE abuts.rest#NIL DO ENDLOOP;
abut ← abuts.first;
offset ← abut.off - lastSection.first.abutMin;
pins ← abut.lastPins;
FOR pins ← pins, pins.rest
WHILE pins#
NIL
DO
pin: WirePin ← pins.first;
sections.first.chan.firstPins ←
CONS
[[pin.wire, pin.min+offset, pin.max+offset, pin.layer], sections.first.chan.firstPins];
ENDLOOP};
IF sections.rest#
NIL
THEN {
abut ← sections.rest.first.abuts.first;
offset ← abut.off - sections.rest.first.abutMin;
pins ← abut.firstPins;
FOR pins ← pins, pins.rest
WHILE pins#
NIL
DO
pin: WirePin ← pins.first;
sections.first.chan.lastPins ←
CONS
[[pin.wire, pin.min+offset, pin.max+offset, pin.layer], sections.first.chan.lastPins];
ENDLOOP};
IF lastSection=
NIL
THEN sections.first.chan.firstPins ←
FilterPins[sections.first.chan.lastPins, firstWires, globals];
IF sections.rest=
NIL
THEN sections.first.chan.lastPins ←
FilterPins[sections.first.chan.firstPins, lastWires, globals];
ENDLOOP;
CoreProperties.PutCellTypeProp[cellType, stackFormProp, form];
CoreRoute.FlushSchPinCache[cellType]; -- Don't Flush, Save for next level
CoreRoute.FlushLayPinCache[cellType]; -- Don't Flush, Save for next level
FOR i:
INT
IN [0..data.size)
DO
CoreRoute.FlushSchPinCache[data[i].type];
CoreRoute.FlushLayPinCache[data[i].type] ENDLOOP;
ShowStackForm[cellType]};
StackLayout: PWCore.LayoutProc = {
data: CoreClasses.RecordCellType ← NARROW[cellType.data];
form: StackForm ← NARROW[CoreProperties.GetCellTypeProp[cellType, stackFormProp]];
primary: LIST OF CD.Object ← NIL;
minSide: Side ← RSide[form.inX, min];
maxSide: Side ← RSide[form.inX, max];
totalLength: REF INT ← NARROW[CoreProperties.GetCellTypeProp[cellType, $TotalLength]];
length: INT ← 0;
chanCnt: INT ← 0;
chanIndex: INT ← 0;
form.auxLabels ← SymTab.Create[];
Count channels and compute starting length for use with totalLength
FOR sections:
LIST
OF StackSection ← form.sec, sections.rest
WHILE sections#
NIL
DO
IF sections.first.chan #
NIL
THEN chanCnt ← chanCnt+1
ELSE {
abuts: LIST OF StackAbutRec ← sections.first.abuts;
FOR abuts ← abuts, abuts.rest
WHILE abuts#
NIL
DO
length ← length + abuts.first.laySize.height ENDLOOP } ENDLOOP;
Make section objects
FOR sections:
LIST
OF StackSection ← form.sec, sections.rest
WHILE sections#
NIL
DO
IF sections.first.chan #
NIL
THEN {
adjustChan: BOOL ← chanIndex+1=chanCnt AND totalLength#NIL;
brLen: INT ← IF adjustChan THEN lambda*totalLength^-length ELSE 0;
rtObj: CD.Object ← MakeStackChannel[cellType, chanIndex, sections.first.chan, brLen];
objSize: CD.Position ← CD.InterestSize[rtObj];
primary ← CONS[rtObj, primary];
length ← length + (IF form.inX THEN objSize.x ELSE objSize.y);
chanIndex ← chanIndex+1;
IF adjustChan
AND length>lambda*totalLength^
THEN
TerminalIO.PutF["*** Total Stack length exceeded by %g lambda.\n",
IO.int[(length/lambda)-totalLength^]]};
FOR abuts:
LIST
OF StackAbutRec ← sections.first.abuts, abuts.rest
WHILE abuts#
NIL
DO
secondary: LIST OF CD.Object ← NIL;
gapMin: INT ← abuts.first.off - sections.first.abutMin;
gapMax: INT ← sections.first.abutMax - abuts.first.off - abuts.first.laySize.width;
length: INT ← abuts.first.laySize.height;
IF gapMax > 0
THEN {
enumSegs:
PROC [eachSeg:
PROC[Segment]] =
{FOR segs ← segs, segs.rest WHILE segs#NIL DO eachSeg[segs.first] ENDLOOP};
segs: Segments ← GetSegs[data.internal, abuts.first.maxPins, form.trunkLayer];
size: CD.Position ← IF form.inX THEN [length,gapMax] ELSE [gapMax,length];
extObj: CD.Object ← CoreRoute.ExtendObject[enumSegs, size, maxSide];
secondary ← CONS[extObj, secondary]};
secondary ← CONS[PWCore.Layout[data[abuts.first.inst].type], secondary];
IF gapMin > 0
THEN {
enumSegs:
PROC [eachSeg:
PROC[Segment]] =
{FOR segs ← segs, segs.rest WHILE segs#NIL DO eachSeg[segs.first] ENDLOOP};
segs: Segments ← GetSegs[data.internal, abuts.first.minPins, form.trunkLayer];
size: CD.Position ← IF form.inX THEN [length,gapMin] ELSE [gapMin, length];
extObj: CD.Object ← CoreRoute.ExtendObject[enumSegs, size, minSide];
secondary ← CONS[extObj, secondary]};
primary ←
CONS[
IF secondary.rest=
NIL
THEN secondary.first
ELSE
IF form.inX
-- pimary inX => secondary inY
THEN PW.CreateNewAbutY[secondary]
ELSE PW.CreateNewAbutX[secondary], primary];
ENDLOOP;
ENDLOOP;
primary ← ReverseObj[primary];
obj ←
IF form.inX
THEN PW.CreateNewAbutX[primary]
ELSE PW.CreateNewAbutY[primary]};