CoreFrameImpl.mesa
Copyright c 1985 by Xerox Corporation. All rights reserved.
Last Edited by Curry, October 4, 1986 7:47:32 pm PDT
Don Curry October 30, 1986 5:37:16 pm PST
DIRECTORY BasicTime, CD, CDOrient, CDBasics, Core, CoreBlock, CoreFrame, CoreGlue, CoreName, CoreOps, CoreProperties, FS, IO, PWCLayoutCheckpoint, PWC, Rope, TypeScript, ViewerIO, WatchStats;
CoreFrameImpl: CEDAR PROGRAM
IMPORTS BasicTime, CDOrient, CDBasics, CoreBlock, CoreFrame, CoreGlue, CoreName, CoreOps, CoreProperties, FS, IO, PWCLayoutCheckpoint, PWC, Rope, TypeScript, ViewerIO, WatchStats
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] = {
name: ROPE ← CoreName.CellNm[frameCT].n;
gap: INTMAX[42 - 2*indent - name.Length[], 2];
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[name];
FOR ii: INT IN [0..gap) DO out.PutChar[IO.SP] ENDLOOP;
LogFrameData[frame, 0, 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["%7g-%g%7g-%g",
IO.int[size.x], IO.char[Rope.Fetch[FreeRope[size.xfree]]],
IO.int[size.y], IO.char[Rope.Fetch[FreeRope[size.yfree]]], ];
out.PutF[" At%7g%7g", IO.int[pos.x], IO.int[pos.y] ];
IF seq.size#0 THEN out.PutF[" %g", IO.char[Rope.Fetch[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]};
CellCached: PUBLIC PROC[name: ROPE] RETURNS[cached: BOOLTRUE] = {
ENABLE FS.Error => {cached ← FALSE; CONTINUE};
file: FS.OpenFile ← FS.Open[ name.Cat["Shell", ".dale"] ];
IF cached
THENFS.Close[file]
ELSE log.PutF["\n%g is not cached", IO.rope[name]]};
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;
cached:  BOOLTRUE;
time[begin]  ← BasicTime.Now[];
vm[begin]  ← WatchStats.GetWatchStats[].vmFree;
IF NOT CellCached[name] THEN RETURN[NIL];
cell  ← RetrieveAndDecorate[name];
frameCT ← NewFrameCell[size: 0, name: name, rec: [cell: cell] ];
[]𡤌oreName.CellNm[frameCT, CoreName.CellNm[cell].n];
IF CoreName.CellNm[cell].n=NIL OR CoreName.CellNm[cell].n#CoreName.CellNm[frameCT].n
THEN Signal[];
time[mid]  ← BasicTime.Now[];
vm[mid]  ← WatchStats.GetWatchStats[].vmFree;
count   ← PWC.CountTransistors[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 ] ]};
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];
PWCLayoutCheckpoint.Store[FCT[frameCT].cell];
FCT[frameCT].cell ← RetrieveAndDecorate[name];
count ← PWC.CountTransistors[FCT[frameCT].cell];
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 ] ]};
RetrieveAndDecorate: PUBLIC PROC[name: ROPE] RETURNS[cell: CT] = {
cell ← PWCLayoutCheckpoint.Retrieve[name];
CoreBlock.MarkSides[cell]};
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 = {Signal[]};
Brings up decorated record cellTypes and sets up Layout procs
RecastFrameHard: PUBLIC Core.RecastProc = {
frame:  Frame ← FCT[me];
name:  ROPE ← CoreName.CellNm[me].n;
cells:  LIST OF CT;
ReOrderFrame[me];
IF frame.cell=NIL THEN {
IF frame.seq.size=0 THEN {Signal[]; RETURN[new]}; -- NIL
FOR i: INT DECREASING IN [0..frame.seq.size) DO
cells ← CONS[RecastFrameHard[frame.seq[i]], cells] ENDLOOP;
frame.cell ← CoreBlock.AbutCellList
[name: name, first: SideSides[frame.first], cellTypes: cells]};
RETURN[frame.cell]};
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 ← PWC.FromLayoutWithoutPublic[ PWC.Layout[me] ];
IF new.class = CoreClasses.recordCellClass THEN RETURN;
new ← PWC.FromLayout[ CoreOps.CopyWire[me.public], PWC.Layout[me] ];
IF new.class = CoreClasses.recordCellClass THEN RETURN;
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  => PWC.SetAbutX[new];
bottom => PWC.SetAbutY[new];
ENDCASE => Signal[] };
RecastFrameHard: PUBLIC Core.RecastProc = {
frame: Frame ← FCT[me];
IF frame.cell#NIL
THEN {Signal[]; RETURN[CoreOps.Recast[frame.cell]]} -- no no
ELSERETURN[FrameCell[me]]};     -- sets frame.cell
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};
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};
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[PWC.InterestSize[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: PUBLIC 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] ];
RotateCellType: PUBLIC PROC[cell: CT, orient: CD.Orientation] RETURNS[new: CT] = {
OrientATOM: ARRAY CD.Orientation OF ATOM = [ -- to match style of PWC procs
$Rot0,  $Rot0X, $Rot90, $Rot90X, $Rot180, $Rot180X,  $Rot270, $Rot270X ];
RotateSides: CoreOps.EachWirePairProc = { -- actualWire, publicWire
oldSides: CoreBlock.Sides ← CoreBlock.GetWireSide[actualWire];
newSides: CoreBlock.Sides ← none;
IF actualWire.size#0 THEN RETURN;
FOR side: Side IN Side DO
IF CoreBlock.OnSide[SideSides[side], oldSides] THEN
newSides ← CoreBlock.AddSide[SideSides[OrientSideSide[orient][side]], newSides]
ENDLOOP;
CoreBlock.PutWireSide[publicWire, newSides]};
new ← PWC.RotateCellType[cell, OrientATOM[orient]];
[]𡤌oreOps.VisitBinding[cell.public, new.public, RotateSides];
CoreBlock.PutCellSide[new, all]};
RotateCellType: PUBLIC PROC[cell: CT, orient: CD.Orientation] RETURNS[new: CT] = {
MakeNew: PROC[oCell: CT, atom: ATOM, partial: CD.Orientation] RETURNS[nCell: 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[partial][side]], newSides]
ENDLOOP;
CoreBlock.PutWireSide[wire, newSides]};
nCell ← PWC.RotateCellType[oCell, atom];
CoreOps.VisitAtomicWires[nCell.public, RotateSides];
CoreBlock.PutCellSide[nCell, all]};
SELECT orient FROM
CDOrient.rotate90,
CDOrient.rotate90X => new ← MakeNew[ cell, $Rot90,  CDOrient.rotate90];
CDOrient.rotate180,
CDOrient.rotate180X => new ← MakeNew[ cell, $Rot180, CDOrient.rotate180];
CDOrient.rotate270,
CDOrient.rotate270X => new ← MakeNew[ cell, $Rot270, CDOrient.rotate270];
ENDCASE    => new ←     cell;
SELECT orient FROM
CDOrient.mirrorX,
CDOrient.rotate90X,
CDOrient.rotate180X,
CDOrient.rotate270X => new ← MakeNew[ new, $FlipX,  CDOrient.mirrorX];
ENDCASE};
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 ← PWC.RotateCellType[new, $Rot90]};
CDOrient.rotate180,
CDOrient.rotate180X => {new ← PWC.RotateCellType[new, $Rot180]};
CDOrient.rotate270,
CDOrient.rotate270X => {new ← PWC.RotateCellType[new, $Rot270]}; ENDCASE;
SELECT orient FROM
CDOrient.mirrorX,
CDOrient.rotate90X,
CDOrient.rotate180X,
CDOrient.rotate270X => {new ← PWC.RotateCellType[new, $FlipX]}; ENDCASE;
obj ← PWC.Layout[new];
IF PWC.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[PWC.InterestSize[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 change %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
IF incr#0 THEN AddExtentionIfNeeded[frame.seq[ii]];
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]];
AddExtentionIfNeeded[fframe.seq[lastTame]];  -- could be too big!!
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]};
AddExtentionIfNeeded: PROC[frameCT: Core.CellType] = {
frame: Frame ← FCT[frameCT];
IF frame.cell#NIL AND frame.data#NIL THEN { -- Extendable glue
glue:  CoreGlue.Glue ← NARROW[frame.data];
size:  CD.Position  ← PWC.InterestSize[frame.cell];
extend: BOOL    ← IF glue.tDir=vertical
THEN frame.size.x#size.x
ELSE frame.size.y#size.y;
IF extend THEN {
extFrame: Frame;
AddExtention[frameCT];
extFrame ← FCT[FCT[frameCT].seq[0]];
extFrame.size.xfree ← extFrame.size.yfree ← fixed} } };
AddExtention: PUBLIC PROC[frameCT: CT] = {
name:  ROPE ← CoreName.CellNm[frameCT].n;
origFrm: Frame ← FCT[frameCT];
newFrm: Frame;
glue:  CoreGlue.Glue ← NARROW[origFrm.data];
origConnSide: 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.data ← NIL;
origFrm.size.xfree ← origFrm.size.yfree ← fixed;
newFrm ← NEW[CoreFrame.FrameRec ← [first: IF glue.tDir=vertical THEN left ELSE bottom]];
frameCT.data ← newFrm;
newFrm.seq ← NEW[CoreFrame.FrameSeq[2]];
newFrm.seq[0] ← SELECT origConnSide 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"]];
SELECT origConnSide FROM
right, top =>
{new: CT ← newFrm.seq[0]; newFrm.seq[0] ← newFrm.seq[1]; newFrm.seq[1] ← new};
ENDCASE;
newFrm.father ← origFrm.father;
FCT[newFrm.seq[0]].father ← FCT[newFrm.seq[1]].father ← frameCT};
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;
TypeScript.ChangeLooks[ViewerIO.GetViewerFromStream[log], 'f];
log.PutF["%g %g\n\n", IO.rope[logName], IO.time[]]};
RETURN[log]};
[ ] ← GetLog[];
END.