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.
STREAM ←
NIL] = {
name: ROPE ← CoreName.CellNm[frameCT].n;
gap: INT ← MAX[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.
STREAM ←
NIL] = {
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:
CT ←
FCT[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: ROPE ← NIL] = {
name ← CoreName.CellNm[frameCT, name].n;
CoreProperties.PutCellTypeProp[frameCT, checkPoint, NEW[BOOL ← TRUE]]};
IsFrameCheckPoint: PUBLIC PROC[frameCT: CT] RETURNS[BOOL] = {
RETURN[CoreProperties.GetCellTypeProp[frameCT, checkPoint]#NIL]};
CellCached:
PUBLIC
PROC[name:
ROPE]
RETURNS[cached:
BOOL ←
TRUE] = {
ENABLE FS.Error => {cached ← FALSE; CONTINUE};
file: FS.OpenFile ← FS.Open[ name.Cat["Shell", ".dale"] ];
IF cached
THEN FS.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: BOOL ← TRUE;
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 ANY ← NIL] = {
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: ATOM ← IF 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: ATOM ← IF 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] ]}
ELSE FOR 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
ELSE RETURN[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=NIL THEN expand ← GetFrameExpandProc[type, fCT];
IF expand=NIL THEN expand ← GetFrameExpandProc[type, fCT.class];
IF expand#NIL THEN 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: ROPE ← IO.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:
CT ←
NIL] = {
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: BOOL ← FALSE;
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
THEN FCT[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 INT ← ALL[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:
BOOL ←
FALSE] = {
FixOneSizeRecursive:
PUBLIC
PROC [fframeCT:
CT]
RETURNS[ffixed1:
BOOL ←
FALSE] = {
fframe: Frame ← FCT[fframeCT];
lastTame: INT ← -1;
wildOrMultTamesFound: BOOL ← FALSE;
horizontal: BOOL ← fframe.first=left OR fframe.first=right;
FOR kid:
INT
IN [0..fframe.seq.size)
DO
SELECT (
IF horizontal
THEN FCT[fframe.seq[kid]].size.xfree
ELSE
FCT[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: BOOL ← TRUE] = {
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.