CoreFrameImpl.mesa
Copyright c 1985 by Xerox Corporation. All rights reserved.
Last Edited by Curry, July 17, 1986 5:13:40 pm PDT
DIRECTORY BasicTime, CCDUtils, CD, CDOrient, CDBasics, Core, CoreBlock, CoreClasses, CoreCreate, CoreFrame, CoreGlue, CoreInstCell, CoreIO, CoreName, CoreOps, CoreProperties, IO, LayoutCheckpoint, PW, PWCore, Rope, ViewerIO, WatchStats, WriteCapa;
CoreFrameImpl: CEDAR PROGRAM
IMPORTS BasicTime, CCDUtils, CDOrient, CDBasics, CoreBlock, CoreClasses, CoreCreate, CoreFrame, CoreGlue, CoreInstCell, CoreIO, CoreName, CoreOps, CoreProperties, IO, LayoutCheckpoint, PW, PWCore, Rope, ViewerIO, WatchStats, WriteCapa
EXPORTS CoreFrame =
BEGIN OPEN CoreFrame;
Signal: SIGNAL = CODE;
frameCellClass: PUBLIC Core.CellClass ←
CoreOps.SetClassPrintProc[
class: NEW[ Core.CellClassRec ← [name: "Frame", recast: RecastFrameSoft]],
proc: ClassPrintProc];
ClassPrintProc: CoreOps.PrintClassProc = {
frame: Frame ← NARROW [data];
LogFrameData[frame, 0, TRUE, out];
FOR ii: INT IN [0..frame.seq.size) DO
LogFCT[frame.seq[ii], 1, 21, out] ENDLOOP};
FreeRope: ARRAY Freedom OF ROPE ← ["fixed", "tame", "wild"];
SideRope: PUBLIC ARRAY Side OF ROPE ← ["BOTTOM", "RIGHT", "TOP", "LEFT"];
LogFCT: PUBLIC PROC[frameCT: CT, indent: INT, lim: INT, out: IO.STREAMNIL] = {
frame: Frame;
IF out=NIL THEN out ← GetLog[];
IF frameCT.class#frameCellClass THEN {CoreOps.PrintCellType[frameCT]; RETURN};
frame ← FCT[frameCT];
CoreOps.PrintIndent[indent, out];
out.PutRope[CoreName.CellNm[frameCT].n]; LogFrameData[frame, 2, FALSE, out];
IF indent<lim THEN FOR i: INT IN [0..frame.seq.size)
DO LogFCT[frame.seq[i], indent+1, lim, out] ENDLOOP};
LogFrameData: PUBLIC PROC[frame: Frame, indent: INT, cr: BOOL, out: IO.STREAMNIL] = {
OPEN frame^;
IF out=NIL THEN out ← GetLog[];
CoreOps.PrintIndent[indent, out, cr];
out.PutF["Size: %8g%8g", IO.int[size.x], IO.int[size.y] ];
out.PutF[" %8g%8g", IO.rope[FreeRope[size.xfree]], IO.rope[FreeRope[size.yfree]] ];
out.PutF[" Pos: %8g%8g", IO.int[pos.x], IO.int[pos.y] ];
IF seq.size#0 THEN out.PutF[" First: %g", IO.rope[SideRope[first]] ]};
FullFrameName: PUBLIC PROC[frameCT: CT] RETURNS[name: ROPE] = {
FOR temp: CTFCT[frameCT].father, FCT[frameCT].father WHILE temp#NIL DO
name ← Rope.Cat[CoreName.CellNm[temp].n, ".", name] ENDLOOP;
name ← name.Cat[CoreName.CellNm[frameCT].n]};
NewFrameCell: PUBLIC PROC[size: INT, name: ROPE, rec: FrameRec ← [ ]]
RETURNS [new: CT] = {
new ← CoreOps.CreateCellType[
class:    frameCellClass,
public:   CoreOps.CreateWires[0],
data:    NEW[FrameRec ← rec],
name:    CoreName.RopeNm[name],
props:    NIL];
FCT[new].seq ← NEW[FrameSeq[size]];
[ ] ← CoreName.CellNm[new, name] };
NewFrameCells: PUBLIC PROC[
cells:  LIST OF CT,
name:  ROPE,
rec:  FrameRec ← [ ] ]
RETURNS [cellType: CT] = {
frame: Frame;
count: INT ← 0;
FOR list: LIST OF CT ← cells, list.rest WHILE list#NIL DO count𡤌ount+1 ENDLOOP;
cellType ← NewFrameCell[count, name, rec];
count ← 0;
frame ← FCT[cellType];
FOR list: LIST OF CT ← cells, list.rest WHILE list#NIL DO
IF list.first=NIL THEN {Signal[]; LOOP};
frame.seq[count] ← list.first; count𡤌ount+1 ENDLOOP };
frameExpandSoftProc: ATOM ← CoreProperties.RegisterProperty[prop: $FrameExpandSoftProc];
frameExpandHardProc: ATOM ← CoreProperties.RegisterProperty[prop: $FrameExpandHardProc];
checkPoint:    ATOM ← CoreProperties.RegisterProperty[prop: $CheckPoint];
MarkFrameCheckPoint: PUBLIC PROC[frameCT: CT, name: ROPENIL] = {
name ← CoreName.CellNm[frameCT, name].n;
CoreProperties.PutCellTypeProp[frameCT, checkPoint, NEW[BOOLTRUE]]};
IsFrameCheckPoint: PUBLIC PROC[frameCT: CT] RETURNS[BOOL] = {
RETURN[CoreProperties.GetCellTypeProp[frameCT, checkPoint]#NIL]};
ReadFrameCache:  PUBLIC PROC[name: ROPE] RETURNS[frameCT: CT] = {
count:  INT ← 0;
Period: TYPE = {begin, mid, end};
time: ARRAY Period OF BasicTime.GMT;
vm: ARRAY Period OF INT;
cell:  CT;
design: CD.Design;
time[begin]  ← BasicTime.Now[];
vm[begin]  ← WatchStats.GetWatchStats[].vmFree;
design ← PW.OpenDesign[name.Cat["Shell"]];
IF design=NIL THEN RETURN[NIL];
cell  ← LayoutCheckpoint.Retrieve[name];
frameCT ← NewFrameCell[size: 0, name: name, rec: [cell: cell] ];
frameCT.properties ← AddPropCopyIfNotPresent[frameCT.properties, cell.properties];
time[mid]  ← BasicTime.Now[];
vm[mid]  ← WatchStats.GetWatchStats[].vmFree;
[]    ← PWCore.Layout[cell];
count   ← CountTransistors[cell.class.recast[cell]];
time[end]  ← BasicTime.Now[];
vm[end]  ← WatchStats.GetWatchStats[].vmFree;
log.PutF["\nReadFrameCache: %g   %g", IO.rope[name], IO.time[]];
log.PutF["\n Begin: vm: %6g %g", IO.int[vm[begin]], IO.time[time[begin]]];
log.PutF["\n Core: vm: %6g %g", IO.int[vm[mid]], IO.time[time[mid]]];
log.PutF["\n Dale: vm: %6g %g", IO.int[vm[end]], IO.time[time[end]]];
log.PutF["\n Cost: vm: %6g", IO.int[ vm[begin]-vm[end] ] ];
log.PutF["\n Xstrs: %g", IO.int[ count ] ]};
WriteCapaProc: PROC[cell: Core.CellType] = {WriteCapa.WriteWireCapa[cell]};
WriteFrameCache: PUBLIC PROC[frameCT: CT] = {
Period: TYPE = {begin, mid, end};
time: ARRAY Period OF BasicTime.GMT;
vm: ARRAY Period OF INT;
count:  INT;
name:  ROPE ← CoreName.CellNm[frameCT].n;
IF name.Length[]=0 THEN Signal[];
time[begin]  ← BasicTime.Now[];
vm[begin]  ← WatchStats.GetWatchStats[].vmFree;
[ ] ← Expand[hard, frameCT];
[ ] ← CoreGlue.RouteHard[frameCT];
[ ] ← CoreName.CellNm[FCT[frameCT].cell, name];
FCT[frameCT].cell.properties ←
AddPropCopyIfNotPresent[FCT[frameCT].cell.properties, frameCT.properties];
count ← CountTransistors[FCT[frameCT].cell];
WriteCapaProc[FCT[frameCT].cell];
LayoutCheckpoint.Store[FCT[frameCT].cell];
FCT[frameCT].cell ← LayoutCheckpoint.Retrieve[name];
FCT[frameCT].seq ← NEW[FrameSeq[0]];
time[mid]  ← BasicTime.Now[];
vm[mid]  ← WatchStats.GetWatchStats[].vmFree;
SafeStorage.ReclaimCollectibleObjects[TRUE, TRUE];
time[end]  ← BasicTime.Now[];
vm[end]  ← WatchStats.GetWatchStats[].vmFree;
log.PutF["\nWriteFrameCache: %g   %g", IO.rope[name], IO.time[]];
log.PutF["\n Start: vm: %6g %g", IO.int[vm[begin]], IO.time[time[begin]]];
log.PutF["\n Built: vm: %6g %g", IO.int[vm[mid]], IO.time[time[mid]]];
log.PutF["\n Cached: vm: %6g %g", IO.int[vm[end]], IO.time[time[end]]];
log.PutF["\n Cost: vm: %6g", IO.int[ vm[begin]-vm[end] ] ];
log.PutF["\n Xstrs: %g", IO.int[ count ] ]};
AddPropCopyIfNotPresent: PROC [old, addends: Core.Properties]
RETURNS [Core.Properties] = {
consume: PROC [prop: ATOM, val: REF ANYNIL] = {
IF CoreProperties.GetProp[old, prop]#NIL THEN RETURN;
old ← CoreProperties.PutProp[old, prop, val]};
CoreProperties.Enumerate[CoreProperties.CopyProps[addends], consume];
RETURN[old]};
SetFrameExpandProc: PUBLIC PROC[type: ExpandType, on: REF, proc: REF ExpandProc] = {
expandProc: ATOMIF type=soft THEN frameExpandSoftProc ELSE frameExpandHardProc;
WITH on SELECT FROM
cell: Core.CellType => {cell.properties ←
CoreProperties.PutProp[cell.properties, expandProc, proc]};
class: Core.CellClass => {class.properties ←
CoreProperties.PutProp[class.properties, expandProc, proc]};
ENDCASE => Signal[]};
GetFrameExpandProc: PUBLIC PROC[type: ExpandType, on: REF] RETURNS[proc: REF ExpandProc] = {
expandProc: ATOMIF type=soft THEN frameExpandSoftProc ELSE frameExpandHardProc;
WITH on SELECT FROM
cell: Core.CellType => {proc ← NARROW[
CoreProperties.GetCellTypeProp[cell, expandProc].value]};
class: Core.CellClass => {proc ← NARROW[
CoreProperties.GetCellClassProp[class, expandProc].value]};
ENDCASE => Signal[]};
RecastFrameSoft: PUBLIC Core.RecastProc = {
frame:  Frame ← FCT[me];
public: Core.Wires;
intOnly: Core.Wires;
instances: CoreCreate.CellInstances;
ReOrderFrame[me];
new ← frame.cell;
IF new#NIL THEN RETURN[new];
IF frame.seq.size=0
THEN {
IF frame.intOnly=NIL THEN RETURN[frame.cell];
log.PutF["\n WARNING: %g has partially disconnected public.",
IO.rope[CoreName.CellNm[frame.cell].n] ];
log.PutRope["\n I will bury the loose ends inside for now."];
instances ← LIST[ CoreCreate.Instance[frame.cell] ]}
ELSEFOR i: INT DECREASING IN [0..frame.seq.size) DO
new ← RecastFrameSoft[frame.seq[i]];
instances ← CONS[CoreCreate.Instance[new], instances] ENDLOOP;
FOR ropes: LIST OF ROPE ← frame.public, ropes.rest WHILE ropes#NIL DO
public ← CONS[CoreOps.CreateWires[0, ropes.first], public] ENDLOOP;
FOR ropes: LIST OF ROPE ← frame.intOnly, ropes.rest WHILE ropes#NIL DO
intOnly ← CONS[CoreOps.CreateWires[0, ropes.first], intOnly] ENDLOOP;
new ← frame.cell ← CoreCreate.Cell[
public:  CoreOps.CreateWire[public],
onlyInternal: CoreOps.CreateWire[intOnly],
instances:  instances,
name:   CoreName.CellNm[me].n ];
CoreBlock.PutCellSide[new, SideSides[frame.first]];
CoreBlock.MergeSides[new];
SELECT frame.first FROM
left  => PWCore.SetAbutX[new];
bottom => PWCore.SetAbutY[new];
ENDCASE => Signal[] };
RecastWithLayout: PUBLIC Core.RecastProc = { Signal[] };
mainly to get rid of persistant identity cells
RecastWithLayout: PUBLIC Core.RecastProc = {
new ← me;
IF new.class = CoreClasses.recordCellClass THEN RETURN;
new ← PWCore.FromLayoutWithoutPublic[ PWCore.Layout[me] ];
IF new.class = CoreClasses.recordCellClass THEN RETURN;
new ← PWCore.FromLayout[ CoreOps.CopyWire[me.public], PWCore.Layout[me] ];
IF new.class = CoreClasses.recordCellClass THEN RETURN;
Signal[]};
RecastFrameHard: PUBLIC Core.RecastProc = {
frame: Frame ← FCT[me];
IF frame.cell#NIL
THENRETURN[CoreOps.Recast[frame.cell]]
ELSERETURN[FrameInst[me].type]};
FrameInst: PUBLIC PROC[frameCT: CT] RETURNS [instance: CoreClasses.CellInstance←NIL] = {
frame:   Frame ← FCT[frameCT];
name:   ROPE ← CoreName.CellNm[frameCT].n;
instances:  CoreClasses.CellInstances;
ReOrderFrame[frameCT];
IF frame.cell=NIL THEN {
IF frame.seq.size=0 THEN {Signal[]; RETURN[instance]}; -- NIL
FOR i: INT DECREASING IN [0..frame.seq.size) DO
instances ← CONS[FrameInst[frame.seq[i]], instances] ENDLOOP;
frame.cell ← CoreBlock.AbutCellInstances
[name: name, first: SideSides[frame.first], instances: instances]};
SELECT frame.cell.class FROM
CoreInstCell.specificGenericCellClass => {
instance ← CoreClasses.SetCellInstanceName[ NEW[CoreClasses.CellInstanceRec ←
[actual: frame.cell.public, type: NARROW[frame.cell.data]] ], name]};
ENDCASE => {
frame.cell ← RecastWithLayout[frame.cell] why recast identities?
instance ← CoreClasses.SetCellInstanceName[ NEW[CoreClasses.CellInstanceRec ←
[actual: frame.cell.public, type: frame.cell] ], name]};
RETURN[instance]};
RecastFrameHard: PUBLIC Core.RecastProc = {
frame:  Frame ← FCT[me];
name:  ROPE ← CoreName.CellNm[me].n;
cells:  LIST OF Core.CellType;
new  ← frame.cell;
ReOrderFrame[me];
IF new#NIL THEN RETURN[new];
IF frame.seq.size=0 THEN {Signal[]; RETURN[frame.cell]}; -- NIL
FOR i: INT DECREASING IN [0..frame.seq.size) DO
cells ← CONS[RecastFrameHard[frame.seq[i]], cells] ENDLOOP;
new ← CoreBlock.AbutCellList[name: name, first: SideSides[frame.first], cellTypes: cells];
frame.cell ← new};
CountTransistors: PUBLIC PROC[cell: CT] RETURNS[count: INT ← 0] = {
IF cell=NIL THEN RETURN[0];
SELECT cell.class FROM
CoreInstCell.specificGenericCellClass => RETURN[CountTransistors[NARROW[cell.data]]];
frameCellClass       => {
frame: Frame ← FCT[cell];
IF frame.seq.size=0 THEN RETURN[CountTransistors[frame.cell]];
FOR child: INT IN [0..frame.seq.size) DO
count ← count + CountTransistors[ frame.seq[child] ] ENDLOOP };
CoreClasses.sequenceCellClass  => {
data: CoreClasses.SequenceCellType ← NARROW[cell.data];
RETURN[data.count*CountTransistors[data.base]]};
CoreClasses.recordCellClass  => {
data: CoreClasses.RecordCellType ← NARROW[cell.data];
FOR child: NAT IN [0..data.size) DO
count ← count + CountTransistors[ data.instances[child].type ] ENDLOOP };
CoreClasses.transistorCellClass => RETURN[1];
CoreClasses.identityCellClass => RETURN[CountTransistors[NARROW[cell.data]]];
CoreIO.importCellClass => {log.PutRope["\nSkipping Imported Transistors\n"]; RETURN[0]};
ENDCASE       => {Signal[]; RETURN[0]}};
ReOrderFrame: PROC[cell: Core.CellType] = {
DualCell: TYPE = RECORD[cell0, cell1: Core.CellType];
frame: Frame;
IF cell.class # frameCellClass THEN RETURN;
frame ← FCT[cell];
SELECT frame.first FROM
right   => frame.first ← left;
top   => frame.first ← bottom;
ENDCASE  => RETURN;
FOR i: INT IN [0..frame.seq.size/2) DO
j: INT ← frame.seq.size-1-i;
[frame.seq[j], frame.seq[i]] ← DualCell[frame.seq[i], frame.seq[j]] ENDLOOP};
Expand: PUBLIC PROC[type: ExpandType, frameCT: CT] = {
expandNodeProc: EnumProc = {
expand: REF ExpandProc ← NIL;
IF expand=NILTHEN expand ← GetFrameExpandProc[type, fCT];
IF expand=NILTHEN expand ← GetFrameExpandProc[type, fCT.class];
IF expand#NILTHEN expand^[type, fCT];
IF fCT.class # frameCellClass THEN Signal[];
RETURN[kids: TRUE, continue: TRUE] };
checkNodeProc: EnumProc = {
IF fCT.class # frameCellClass THEN Signal[]};
IF IsCheckPointFrame[frameCT] THEN IF ReadCheckPoint[frameCT] THEN RETURN;
[]𡤎numFrame[frameCT, expandNodeProc];
[]𡤎numFrame[frameCT, checkNodeProc]};
NameFrame: PUBLIC PROC[cell: CT, root: ROPE ← NIL] = {
name: ROPE ← CoreName.CellNm[cell].n;
IF name=NIL THEN {name ← root; []𡤌oreName.CellNm[cell, name]};
IF name=NIL THEN RETURN;
SELECT cell.class FROM
frameCellClass       => {
frame: Frame ← FCT[cell];
IF frame.cell#NIL THEN NameFrame[frame.cell, name.Cat[".RC"]];
FOR field: INT IN [0..frame.seq.size) DO
subName: ROPEIO.PutFR["%g[%g]", IO.rope[name], IO.int[field]];
NameFrame[frame.seq[field], subName]; ENDLOOP};
CoreClasses.recordCellClass  => {
data: CoreClasses.RecordCellType ← NARROW[cell.data];
FOR child: NAT IN [0..data.size) DO
count ← count + CountTransistors[ data.instances[child].type ] ENDLOOP };
ENDCASE};
Fetch: PUBLIC PROC[cell: CT, subCellName: ROPE] RETURNS[subCell: CTNIL] = {
fetchNodeProc: EnumProc = {
IF CoreName.CellNm[fCT].n=subCellName THEN
{subCell ← fCT; RETURN[FALSE, FALSE]} };
subCellName ← CoreName.RopeNm[subCellName];
[]𡤎numFrame[cell, fetchNodeProc] };
Log2: PROC [n: INT] RETURNS [INT] = {RETURN [IF n<=1 THEN 0 ELSE 1 + Log2[n / 2]]};
Exp2: PROC [n: INT] RETURNS [INT] = {RETURN [IF n<=0 THEN 1 ELSE 2 * Exp2[n-1]]};
RotateFrame: PUBLIC PROC[frameCT: CT, orient: CD.Orientation ← CD.original] = {
ReSeq: PROC = {
TwoFrames: TYPE = RECORD[f0, f1: CT];
FOR i: INT IN [0..frame.seq.size/2) DO
[frame.seq[frame.seq.size-i-1], frame.seq[i]] ←
TwoFrames[frame.seq[i], frame.seq[frame.seq.size-i-1]]; ENDLOOP};
frame: Frame ← FCT[frameCT];
orient ← CDOrient.ComposeOrient[frame.orient, orient];
frame.orient ← CDOrient.original;
IF frame.cell#NIL THEN { -- In this case, child frames are ignored
IF orient=CDOrient.original THEN RETURN;
frame.cell ← RotateCellType[frame.cell, orient];
frame.size ← FixedSize[CCDUtils.CellSize[frame.cell]];
RETURN};
IF frame.seq.size = 0 THEN { -- Data must be glue
IF orient=CDOrient.original THEN RETURN;
IF frame.data=NIL THEN ERROR;
WITH frame.data SELECT FROM
glue: CoreGlue.Glue => {
OPEN glue;
srcs: ARRAY Side OF Side ← OrientSideSide[CDOrient.InverseOrient[orient]];
glue.type ← [type[srcs[bottom]], type[srcs[right]], type[srcs[top]], type[srcs[left]] ];
glue.cell ← [cell[srcs[bottom]], cell[srcs[right]], cell[srcs[top]], cell[srcs[left]] ];
FOR side: Side IN Side DO
IF cell[side]#NIL AND type[side]=chan
THEN cell[side] ← RotateCellType[cell[side], orient]; -- for chan cells
ENDLOOP;
SELECT orient FROM
CDOrient.rotate90,
CDOrient.rotate90X,
CDOrient.rotate270,
CDOrient.rotate270X => {
RopePair: TYPE = RECORD[r0, r1: ROPE];
[params.branchLayer, params.trunkLayer] ← RopePair[
params.trunkLayer, params.branchLayer];
frame.size   ← FlipSize[frame.size];
tDir ← IF tDir=horizontal THEN vertical ELSE horizontal};
ENDCASE };
ENDCASE => ERROR;
RETURN};
frame.first ← OrientSideSide[orient][frame.first];
ReOrderFrame[frameCT]; -- first ← left or bottom
FOR i: INT IN [0..frame.seq.size) DO RotateFrame[frame.seq[i], orient] ENDLOOP};
OrientSideSide: ARRAY CD.Orientation OF ARRAY Side OF Side = [
[bottom, right,  top,  left],
[bottom, left,  top,  right],
[right, top,  left,  bottom],
[left,  top,  right,  bottom],
[top,  left,  bottom, right],
[top,  right,  bottom, left],
[left,  bottom, right,  top],
[right, bottom, left,  top] ];
OrientSideSide: ARRAY CD.Orientation OF ARRAY Side OF Side = [
CDOrient.original:  [bottom, right,  top,  left],
CDOrient.mirrorX:  [bottom, left,  top,  right],
CDOrient.rotate90:  [right, top,  left,  bottom],
CDOrient.rotate90X:  [left,  top,  right,  bottom],
CDOrient.rotate180:  [top,  left,  bottom, right],
CDOrient.rotate180X: [top,  right,  bottom, left],
CDOrient.rotate270:  [left,  bottom, right,  top],
CDOrient.rotate270X: [right, bottom, left,  top] ];
RotateCellType: PUBLIC PROC[cell: CT, orient: CD.Orientation] RETURNS[new: CT] = {
RotateSides: PROC[wire: Core.Wire] = {
oldSides: CoreBlock.Sides ← CoreBlock.GetWireSide[wire];
newSides: CoreBlock.Sides ← none;
FOR side: Side IN Side DO
IF CoreBlock.OnSide[SideSides[side], oldSides] THEN
newSides ← CoreBlock.AddSide[SideSides[OrientSideSide[orient][side]], newSides]
ENDLOOP;
CoreBlock.PutWireSide[wire, newSides]};
new ← cell;
SELECT orient FROM
CDOrient.rotate90,
CDOrient.rotate90X => {new ← PWCore.RotateCellType[new, $Rot90]};
CDOrient.rotate180,
CDOrient.rotate180X => {new ← PWCore.RotateCellType[new, $Rot180]};
CDOrient.rotate270,
CDOrient.rotate270X => {new ← PWCore.RotateCellType[new, $Rot270]}; ENDCASE;
SELECT orient FROM
CDOrient.mirrorX,
CDOrient.rotate90X,
CDOrient.rotate180X,
CDOrient.rotate270X => {new ← PWCore.RotateCellType[new, $FlipX]}; ENDCASE;
IF new=cell THEN RETURN[new];
CoreOps.VisitAtomicWires[new.public, RotateSides];
CoreBlock.PutCellSide[new, all]}; -- For this identity cellType
Rotate: PUBLIC PROC[cell: CT, orient: CD.Orientation] RETURNS[new: CT] = {
RotateSides: PROC[wire: Core.Wire] = {
oldSides: CoreBlock.Sides ← CoreBlock.GetWireSide[wire];
newSides: CoreBlock.Sides ← none;
FOR side: Side IN Side DO
IF CoreBlock.OnSide[SideSides[side], oldSides] THEN
newSides ← CoreBlock.AddSide[SideSides[OrientSideSide[orient][side]], newSides]
ENDLOOP;
CoreBlock.PutWireSide[wire, newSides]};
obj: CD.Object;
new ← cell;
WHILE new.class#CoreClasses.recordCellClass DO new ← CoreOps.Recast[new] ENDLOOP;
SELECT orient FROM
CDOrient.rotate90,
CDOrient.rotate90X => {new ← PWCore.RotateCellType[new, $Rot90]};
CDOrient.rotate180,
CDOrient.rotate180X => {new ← PWCore.RotateCellType[new, $Rot180]};
CDOrient.rotate270,
CDOrient.rotate270X => {new ← PWCore.RotateCellType[new, $Rot270]}; ENDCASE;
SELECT orient FROM
CDOrient.mirrorX,
CDOrient.rotate90X,
CDOrient.rotate180X,
CDOrient.rotate270X => {new ← PWCore.RotateCellType[new, $FlipX]}; ENDCASE;
obj ← PWCore.Layout[new];
IF PWCore.FromLayoutWithoutPublic[obj]#new THEN Signal[];
CoreOps.VisitAtomicWires[new.public, RotateSides];
CoreBlock.PutCellSide[new, all]}; -- For this identity cellType
GetSize: PUBLIC PROC[frameCT: CT] = {
variable: BOOLFALSE;
dad, son: Size;
frame: Frame ← FCT[frameCT];
horizontal: BOOL ← frame.first=left OR frame.first=right;
glue: CoreGlue.Glue ← NARROW[frame.data];
IF frame.cell#NIL THEN {
frame.size ← FixedSize[CCDUtils.CellSize[frame.cell]];
IF glue#NIL THEN IF glue.tDir=vertical
THEN frame.size.xfree ← tame
ELSE frame.size.yfree ← tame;
RETURN};
IF frame.seq.size = 0 THEN {
IF glue=NIL THEN {Signal[]; RETURN};
frame.size ← TameSize[];
IF glue.class=chan OR glue.class=pwr THEN IF glue.tDir=vertical
THEN frame.size.xfree ← wild
ELSE frame.size.yfree ← wild;
IF frame.size.x < 1 OR frame.size.y < 1 THEN {Signal[]; frame.data ← NIL};
RETURN};
dad ← [0, 0, fixed, tame];
FOR i: INT IN [0..frame.seq.size) DO -- Normalize sons to x sequences for computations
GetSize[frame.seq[i]];
son ← IF horizontal
THENFCT[frame.seq[i]].size
ELSE FlipSize[FCT[frame.seq[i]].size];
CheckXSeqForExpansionError[dad, son, frame.seq[i]];
dad.xfree ← MAX[dad.xfree, son.xfree]; -- fixed, tame, wild
dad.x  ← dad.x + son.x;
dad.yfree ← IF MIN[dad.yfree,son.yfree]=fixed THEN fixed ELSE MAX[dad.yfree,son.yfree];
dad.y  ← MAX[dad.y, son.y];
ENDLOOP;
FOR i: INT IN [0..frame.seq.size) DO
son ← IF ~horizontal
THEN FlipSize[FCT[frame.seq[i]].size] ELSE FCT[frame.seq[i]].size;
IF dad.yfree=fixed AND son.yfree=wild THEN {
log.PutF["\n WARNING: Limited wild %g width",
IO.rope[ IF horizontal THEN "Y" ELSE "X" ]];
LogFCT[frameCT, 0, 2, log];
log.PutRope["\n"]; EXIT};
ENDLOOP;
frame.size ← IF horizontal THEN dad ELSE FlipSize[dad]};
CheckXSeqForExpansionError: PROC[size1, size2: Size, frameCT: CT] = {
IF (size1.y > size2.y AND size2.yfree=fixed) OR
(size2.y > size1.y AND size1.yfree=fixed) THEN {
log.PutF["\n ERROR: Size of %g not expandable",
IO.rope[CoreName.CellNm[frameCT].n]];
LogFCT[FCT[frameCT].father, 0, 2, log];
log.Flush[];
Signal[]} };
ReSize: PUBLIC PROC[frameCT: CT] = {
dad, son: Size;
freedom: Freedom;
oneVariable: BOOL;
cnt: ARRAY Freedom OF INTALL[0];
length, diff: INT ← 0;
frame: Frame ← FCT[frameCT];
horizontal: BOOL ← frame.first=left OR frame.first=right;
IF frame.seq.size = 0 THEN RETURN;
dad ← IF horizontal THEN frame.size ELSE FlipSize[frame.size];    -- norm
FOR ii: INT IN [0..frame.seq.size) DO
son ← FCT[frame.seq[ii]].size;
son ← IF horizontal THEN son ELSE FlipSize[son];       -- norm
CheckXSeqForExpansionError[dad, son, frame.seq[ii]];
length ← length + son.x;
cnt[son.xfree] ← cnt[son.xfree] + 1;
SELECT dad.yfree FROM
wild  => IF son.yfree=fixed THEN Signal[]; -- how can this happen?
tame  => IF son.yfree#tame THEN Signal[]; -- how can this happen?
ENDCASE;
IF (dad.yfree >= son.yfree) AND (dad.y=son.y) THEN LOOP;
log.PutF["\n %g width changed from %6g %6g",
IO.rope [IF horizontal THEN "Y" ELSE "X"],
IO.int[son.y], IO.rope[FreeRope[son.yfree]] ];
son.yfree ← MIN[dad.yfree, son.yfree];
son.y  ← MAX[dad.y, son.y];
log.PutF[" to %6g %6g in: %g",
IO.int[son.y], IO.rope[FreeRope[son.yfree]], IO.rope [CoreName.CellNm[frame.seq[ii]].n] ];
FCT[frame.seq[ii]].size ← IF horizontal THEN son ELSE FlipSize[son]; -- denorm
ENDLOOP;
diff ← dad.x - length;
FOR freedom DECREASING IN Freedom DO IF cnt[freedom]>0 THEN EXIT ENDLOOP;
oneVariable ← (cnt[tame]=1 AND cnt[wild]=0) OR (cnt[tame]=0 AND cnt[wild]=1);
IF diff<0 THEN Signal[];
IF diff>0 OR diff=0 AND dad.xfree = fixed AND oneVariable THEN {
SELECT dad.xfree FROM
wild, tame => IF freedom#dad.xfree THEN Signal[];
ENDCASE;
FOR ii: INT IN [0..frame.seq.size) WHILE cnt[freedom] > 0 DO
incr: INT ← diff/cnt[freedom];
son ← FCT[frame.seq[ii]].size;
son ← IF horizontal THEN son ELSE FlipSize[son];      -- norm;
IF son.xfree#freedom THEN LOOP;
log.PutF["\n %g length changed from %6g %6g",
IO.rope[IF horizontal THEN "X" ELSE "Y"],
IO.int[son.x], IO.rope[FreeRope[son.xfree]] ];
IF oneVariable THEN son.xfree ← dad.xfree;
son.x ← son.x + incr;
log.PutF[" to %6g %6g in: %g",
IO.int[son.x], IO.rope[FreeRope[son.xfree]], IO.rope [CoreName.CellNm[frame.seq[ii]].n] ];
diff ← diff - incr;
cnt[freedom] ← cnt[freedom] - 1;
FCT[frame.seq[ii]].size ← IF horizontal THEN son ELSE FlipSize[son]; -- denorm
ENDLOOP;
IF diff#0 THEN ERROR};
FOR i: INT IN [0..frame.seq.size) DO ReSize[frame.seq[i]] ENDLOOP };
RePos: PUBLIC PROC[frameCT: CT, new: CD.Position] = {
cng, pos: CD.Position;
frame:  Frame ← FCT[frameCT];
cng ← [new.x-frame.pos.x, new.y-frame.pos.y];
pos ← frame.pos ← new;
IF frame.seq.size=0 THEN RETURN;
FOR side: Side IN Side DO
IF frame.shell.pins[side]=NIL
THEN LOOP
ELSE FOR pin: INT IN [0..frame.shell.pins[side].seq.size) DO
frame.shell.pins[side][pin].pos.x ← frame.shell.pins[side][pin].pos.x + cng.x;
frame.shell.pins[side][pin].pos.y ← frame.shell.pins[side][pin].pos.y + cng.y;
ENDLOOP
ENDLOOP; RETURN};
FOR i: INT IN [0..frame.seq.size) DO
RePos[frame.seq[i], pos];
SELECT frame.first FROM
left, right => pos.x ← pos.x + FCT[frame.seq[i]].size.x;
top, bottom => pos.y ← pos.y + FCT[frame.seq[i]].size.y;
ENDCASE ENDLOOP };
FixOneSize: PUBLIC PROC [frameCT: CT] RETURNS[fixed1: BOOLFALSE] = {
FixOneSizeRecursive: PUBLIC PROC [fframeCT: CT] RETURNS[ffixed1: BOOLFALSE] = {
fframe: Frame ← FCT[fframeCT];
lastTame:      INT ← -1;
wildOrMultTamesFound: BOOLFALSE;
horizontal: BOOL ← fframe.first=left OR fframe.first=right;
FOR kid: INT IN [0..fframe.seq.size) DO
SELECT (IF horizontal
THENFCT[fframe.seq[kid]].size.xfree
ELSEFCT[fframe.seq[kid]].size.yfree) FROM
fixed  => LOOP;
wild  => wildOrMultTamesFound ← TRUE;
ENDCASE => {IF lastTame#-1 THEN wildOrMultTamesFound ← TRUE; lastTame←kid};
ENDLOOP;
IF lastTame#-1 AND wildOrMultTamesFound THEN {
selectedFrame: Frame ← FCT[fframe.seq[lastTame]];
IF horizontal
THEN {selectedFrame.size.xfree ← fixed; log.PutRope["\n X length"]}
ELSE {selectedFrame.size.yfree ← fixed; log.PutRope["\n Y length"]};
log.PutF[" FIXED in %g", IO.rope[CoreName.CellNm[fframe.seq[lastTame]].n]];
IF selectedFrame.cell#NIL AND selectedFrame.data#NIL THEN { -- Extendable glue
glue:  CoreGlue.Glue ← NARROW[selectedFrame.data];
size:  CD.Position  ← CCDUtils.CellSize[selectedFrame.cell];
extend: BOOL    ← IF glue.tDir=vertical
THEN selectedFrame.size.x#size.x
ELSE selectedFrame.size.y#size.y;
IF extend THEN {
extFrame: Frame;
AddExtention[fframe.seq[lastTame]];
extFrame ← FCT[FCT[fframe.seq[lastTame]].seq[0]];
extFrame.size.xfree ← extFrame.size.yfree ← fixed} };
ReSize[fframeCT]; RETURN[TRUE]};
FOR kid: INT IN [0..fframe.seq.size) WHILE NOT ffixed1
DO ffixed1 ← FixOneSizeRecursive[fframe.seq[kid]] ENDLOOP};
frame: Frame ← FCT[frameCT];
IF FixOneSizeRecursive[frameCT] THEN RETURN[TRUE];
IF frame.size.xfree=tame
THEN {frame.size.xfree𡤏ixed; ReSize[frameCT]; RETURN[TRUE]};
IF frame.size.yfree=tame
THEN {frame.size.yfree𡤏ixed; ReSize[frameCT]; RETURN[TRUE]};
RETURN[FALSE]};
AddExtention: PROC[frameCT: Core.CellType] = {
name:  ROPE ← CoreName.CellNm[frameCT].n;
origFrm: Frame ← FCT[frameCT];
newFrm: Frame;
glue:  CoreGlue.Glue ← NARROW[origFrm.data];
extSide: Side ← (IF glue.tDir=vertical
THEN IF glue.type[left]  = conn THEN left  ELSE right
ELSE IF glue.type[bottom] = conn THEN bottom ELSE top);
origFrm.size.xfree ← origFrm.size.yfree ← fixed;
newFrm   ← NEW[CoreFrame.FrameRec ← [first: extSide]];
frameCT.data ← newFrm;
newFrm.seq ← NEW[CoreFrame.FrameSeq[2]];
newFrm.seq[0] ← SELECT extSide FROM
left  => CoreGlue.CellProc[name: name.Cat["Ext"], l: ext, r: conn],
right  => CoreGlue.CellProc[name: name.Cat["Ext"], r: ext, l: conn],
top  => CoreGlue.CellProc[name: name.Cat["Ext"], t: ext, b: conn],
bottom => CoreGlue.CellProc[name: name.Cat["Ext"], b: ext, t: conn],
ENDCASE => ERROR;
Expand[hard, newFrm.seq[0]];
newFrm.seq[1] ← CoreOps.SetCellTypeName[
NEW [Core.CellTypeRec ← [frameCT.class, NIL, origFrm]], name.Cat["Orig"]];
newFrm.father ← origFrm.father;
origFrm.father ← FCT[newFrm.seq[0]].father ← frameCT;
origFrm.data ← NIL};
TellKidsAboutDad: PUBLIC PROC [frameCT: CT] = {
dad: Frame ← FCT[frameCT];
FOR kid: INT IN [0..dad.seq.size)
DO FCT[dad.seq[kid]].father ← frameCT; TellKidsAboutDad[dad.seq[kid]] ENDLOOP};
Neighbor: PUBLIC PROC [frameCT: CT, side: Side] RETURNS[neighborCT: CT, ok: BOOL] = {
NeighborCheck: PROC[fCT: CT] RETURNS[type: {eq, ok, out}] = {
frame: Frame ← FCT[fCT];
negh: CD.Rect ← CDBasics.RectAt[frame.pos, [frame.size.x,frame.size.y]];
SELECT neighborSide FROM
right  => {
IF seg.x2=negh.x2 AND seg.y1=negh.y1 AND seg.y2=negh.y2 THEN RETURN[eq];
IF seg.x2 NOT IN (negh.x1 .. negh.x2] THEN RETURN[out]};
left  => {
IF seg.x1=negh.x1 AND seg.y1=negh.y1 AND seg.y2=negh.y2 THEN RETURN[eq];
IF seg.x1 NOT IN [negh.x1 .. negh.x2) THEN RETURN[out]};
top  => {
IF seg.y2=negh.y2 AND seg.x1=negh.x1 AND seg.x2=negh.x2 THEN RETURN[eq];
IF seg.y2 NOT IN (negh.y1 .. negh.y2] THEN RETURN[out]};
bottom  => {
IF seg.y1=negh.y1 AND seg.x1=negh.x1 AND seg.x2=negh.x2 THEN RETURN[eq];
IF seg.y1 NOT IN [negh.y1 .. negh.y2) THEN RETURN[out]};
ENDCASE;
SELECT neighborSide FROM
right, left => {
IF seg.y1 NOT IN [negh.y1 .. negh.y2) THEN RETURN[out];
IF seg.y2 NOT IN (negh.y1 .. negh.y2] THEN RETURN[out];
RETURN[ok]};
top, bottom => {
IF seg.x1 NOT IN [negh.x1 .. negh.x2) THEN RETURN[out];
IF seg.x2 NOT IN (negh.x1 .. negh.x2] THEN RETURN[out];
RETURN[ok]};
ENDCASE };
leaf:   Frame ← FCT[frameCT];
leafNm:  ROPE ← CoreName.CellNm[frameCT].n;
neighborSide: Side  ← OppSide[side];
seg:   CD.Rect ← CDBasics.RectAt[leaf.pos, [leaf.size.x,leaf.size.y]];
SELECT side FROM
top  => seg.y1 ← seg.y2;
bottom => seg.y2 ← seg.y1;
right  => seg.x1 ← seg.x2;
left  => seg.x2 ← seg.x1;
ENDCASE;
FOR neighborCT ← leaf.father, FCT[neighborCT].father WHILE neighborCT#NIL DO
SELECT NeighborCheck[neighborCT] FROM
ok   => EXIT;
out  => LOOP;
ENDCASE => ERROR REPEAT FINISHED => {
log.PutF["\n ERROR: %g side neighbor of %g is external to frame",
IO.rope[SideRope[side]], IO.rope[leafNm]];
RETURN[NIL, FALSE]} ENDLOOP;
DO
neighbor: Frame ← FCT[neighborCT];
IF neighbor.seq.size=0 THEN RETURN[neighborCT, FALSE];
FOR i: INT IN [0..neighbor.seq.size) DO
SELECT NeighborCheck[neighbor.seq[i]] FROM
out  => LOOP;
eq   => {neighborCT ← neighbor.seq[i]; GOTO Found};
ENDCASE => {neighborCT ← neighbor.seq[i]; EXIT};
REPEAT Found=> EXIT; FINISHED => {
log.PutF["\n ERROR: %g side neighbor of %g can't be identified",
IO.rope[SideRope[side]], IO.rope[leafNm]];
RETURN[NIL, FALSE]} ENDLOOP;
ENDLOOP;
RETURN[neighborCT, TRUE]};
FlattenOnce: PUBLIC PROC[frameCT: CT] RETURNS[new: Frame] =
{new ← TestMergeNodes[frame]};
TestMergeNodes: PUBLIC PROC[frameCT: CT, testProc: TestMergeProc ← NIL]
RETURNS[new: Frame] ~ {
nlist: LIST OF REF;
elist: LIST OF Frame;
xory: XorY ← y;
count: CARDINAL;
FOR index: CARDINAL IN [0..frame.seq.size) DO
IF testProc=NIL OR testProc[frame[index]]
THEN {
IF xory#frame[index].xory THEN ERROR;
FOR element: CARDINAL IN [0..frame[index].seq.size)
DO elist ← CONS[frame[index][element], elist] ENDLOOP}
ELSE {
IF elist#NIL THEN nlist ← CONS[elist, nlist];
elist ← NIL;
nlist ← CONS[frame[index], nlist]};
REPEAT FINISHED => IF elist#NIL THEN nlist ← CONS[elist, nlist] ENDLOOP;
count ← 0;
FOR tlist: LIST OF REF ← nlist, tlist.rest WHILE tlist#NIL DO count ← count+1 ENDLOOP;
new ← NewFrame[count, frame.xory, frame.name, frame.data, frame.unordered];
FOR node: CARDINAL DECREASING IN [0..new.seq.size) DO
WITH nlist.first SELECT FROM
list: LIST OF Frame => {
cnt: CARDINAL ← 0;
FOR tlist: LIST OF Frame ← list, tlist.rest WHILE tlist#NIL
DO cnt ← cnt+1 ENDLOOP;
new[node] ← NewFrame[cnt, xory, "Connections", , list.first.unordered];
FOR element: CARDINAL DECREASING IN [0..new[node].seq.size)
DO new[node][element] ← list.first; list ← list.rest ENDLOOP};
plaFrame: Frame => {new[node] ← plaFrame};
ENDCASE => ERROR;
nlist ← nlist.rest ENDLOOP};
EnumFrame: PUBLIC PROC[fCT: CT, proc: EnumProc]
RETURNS[kids, continue: BOOLTRUE] = {
frame: Frame;
[kids, continue] ← proc[fCT];
IF NOT continue  THEN RETURN[FALSE, FALSE];
IF NOT kids   THEN RETURN[FALSE, TRUE];
frame ← FCT[fCT];
FOR field: INT IN [0..frame.seq.size) DO
IF NOT EnumFrame[frame.seq[field], proc].continue THEN RETURN[FALSE, FALSE];
ENDLOOP;
RETURN[TRUE, TRUE]};
NextSide: PUBLIC PROC [side: Side] RETURNS [next: Side] =
{RETURN[SELECT side FROM bottom=>right, right=>top, top=>left, left=>bottom,
ENDCASE=>ERROR]};
PrevSide: PUBLIC PROC [side: Side] RETURNS [prev: Side] =
{RETURN[SELECT side FROM bottom=>left, left=>top, top=>right, right=>bottom,
ENDCASE=>ERROR]};
OppSide: PUBLIC PROC [side: Side] RETURNS [opp: Side] =
{RETURN[SELECT side FROM left=>right, right=>left, top=>bottom, bottom=>top,
ENDCASE=>ERROR]};
log:  IO.STREAM ← NIL;
GetLog: PUBLIC PROC RETURNS[IO.STREAM] = {
logName: ROPE ← "CoreFrame.log";
IF log=NIL THEN {
log ← ViewerIO.CreateViewerStreams[logName, NIL, logName].out;
log.PutF["%g %g\n\n", IO.rope[logName], IO.time[]]};
RETURN[log]};
[ ] ← GetLog[];
END.