CDFrameImpl:
CEDAR
PROGRAM
IMPORTS Basics, CD, CDBasics, CDCells, CDCommandOps, CDCreateLabels, CDDirectory, CDFrame, CDIO, CDMenus, CDOps, CDOrient, CDPinObjects, CDRects, CDSequencer, CDSil, CDSimpleOps, CMosB, Commander, CommandTool, FS, ImagerFont, IO, NodeProps, PutGet, PW, PWPins, Real, RedBlackTree, Rope, TerminalIO, VFonts, ViewerIO
EXPORTS CDFrame =
EXPORTS CDFrame SHARES CDSilTextCommands =
BEGIN OPEN CDFrame;
NewFrame:
PUBLIC
PROC
[size:
INT, xory: XorY, name:
IO.
ROPE, data:
REF←
NIL, unord:
BOOL←
FALSE]
RETURNS [new: Frame] = {
new ← NEW[FrameSeq[size]];
new.xory ← xory;
new.data ← data;
new.unordered ← unord;
new.shell ← NEW[ShellRec ← [name: name]] };
NewExpandFrame:
PUBLIC
PROC[name:
IO.
ROPE, proc: ExpandProc]
RETURNS [frame: Frame] = {
frame ← NEW[FrameSeq[0]];
frame.shell ← NEW[ShellRec ← [name: name]];
IF proc # NIL THEN frame.data ← NEW[ExpandProc ← proc]};
NewObjectFrame:
PUBLIC
PROC[cell:
CD.Object]
RETURNS[frame: Frame] = {
frame ← NEW[FrameSeq[0]];
frame.data ← cell;
frame.shell ← ShellFromObject[cell]};
NewShellFileFrame:
PUBLIC
PROC[name:
IO.
ROPE]
RETURNS [frame: Frame] = {
frame ← NEW[FrameSeq[0]];
frame.shell ← NEW[ShellRec ← [name: name]];
frame.data ← ShellFromFile[name]};
NextIDIndex: INT ← 0;
ID:
PUBLIC
PROC[name:
IO.
ROPE]
RETURNS[unique:
IO.
ROPE] = {
unique ← IO.PutFR["%g%g", IO.rope[name], IO.int[NextIDIndex]];
NextIDIndex ← NextIDIndex+1};
Glue:
PUBLIC
PROC[
name: IO.ROPE ← NIL,
l,r,b,t: GlueSideType ← cap, -- cap conn ext chan sum diff
bObj,rObj,tObj,lObj: CD.Object ← NIL,
tDir: PWRoute.HorV ← horizontal, -- vertical horizontal
tLayer: IO.ROPE ← NIL, -- metal metal2 poly
bLayer: IO.ROPE ← NIL,
xlate:
BOOL ←
FALSE ]
--
metal2
poly metal
RETURNS [new: Frame] = {
glue: REF GlueSpec;
IF tLayer=NIL THEN tLayer ← IF tDir=horizontal THEN "metal" ELSE "metal2";
IF bLayer=NIL THEN bLayer←IF Rope.Equal[tLayer, "metal"] THEN "metal2" ELSE "metal";
glue ←
NEW[GlueSpec ← [
tDir: tDir,
type: [b,r,t,l],
obj: [bObj,rObj,tObj,lObj],
params: NEW[PWRoute.RouterParamsRec ← [trunkLayer: tLayer, branchLayer:bLayer]]]];
SetGlueClass[glue];
IF xlate THEN IF glue.class#ext THEN Signal[] ELSE glue.class ← xlt;
IF name=
NIL
OR name.Length[]=0
THEN name ←
SELECT glue.class
FROM
fill => ID["Fill-"],
ext => ID["Ext-"],
xlt => ID["Xlt-"],
chan => ID["Chan-"],
pwr => ID["Pwr-"],
sb => ID["SBox-"],
ENDCASE => ID["Bad-"];
new ← NewFrame[0, x, name, glue];
new.shell.size ← IF glue.class=chan OR glue.class=pwr THEN WildSize[] ELSE TameSize[]};
font1: Imager.Font ← VFonts.EstablishFont
[family:"Helvetica", size: 7, bold: TRUE, italic: FALSE, defaultOnFailure: FALSE];
font2: Imager.Font ← VFonts.EstablishFont
[family:"Helvetica", size: 14, bold: TRUE, italic: FALSE, defaultOnFailure: FALSE];
SetGlueClass:
PUBLIC
PROC[glue:
REF GlueSpec] = {
OPEN glue;
Type: PROC[side: Side]
RETURNS[GlueSideType] = {
SELECT type[side]
FROM
pwr => RETURN[conn];
sum, diff => RETURN[chan];
ENDCASE => RETURN[type[side]]};
eqS: BOOL ← (Type[left] = Type[right]) OR (Type[top] = Type[bottom]);
cnt: ARRAY GlueSideType OF INT ← ALL[0];
FOR side: Side
IN Side
DO
cnt[type[side]] ← cnt[type[side]] +1;
IF type[side]=ext
AND type[OppSide[side]]#conn
THEN {class ← bad; Signal[]; RETURN} ENDLOOP;
IF cnt[pwr]>1 THEN {class ← bad; Signal[]; RETURN};
SELECT
(((cnt[conn]+cnt[pwr]) *10 +
cnt[ext]) *10 +
cnt[cap]) *10 +
cnt[chan] + cnt[sum] + cnt[diff] FROM
4000 => {class ← sb};
3100 => {class ← sb};
3010 => {class ← sb};
2200 => {class ← IF eqS THEN bad ELSE sb};
2110 => {class ← IF eqS THEN bad ELSE sb};
2020 => {class ← IF ~eqS THEN sb ELSE chan};
2011 => {class ← IF ~eqS THEN bad ELSE chan};
2002 => {class ← IF ~eqS THEN bad ELSE chan};
1120 => {class ← IF ~eqS THEN bad ELSE ext};
1111 => {class ← chan};
1102 => {class ← IF ~eqS THEN bad ELSE chan};
1021 => {class ← IF eqS THEN bad ELSE chan};
1012 => {class ← IF ~eqS THEN bad ELSE chan};
0040 => {class ← fill};
0022 => {class ← IF ~eqS THEN bad ELSE chan};
ENDCASE => {class ← bad};
IF class=chan
THEN
IF cnt[chan]+cnt[sum]+cnt[diff]=0
THEN {IF (tDir=vertical) = (type[left] = cap AND type[right] = cap) THEN Signal[]}
ELSE {IF (tDir=vertical) = (Type[left] = chan OR Type[right] = chan) THEN Signal[]};
IF class=chan AND cnt[pwr]#0 THEN class←pwr;
IF class=bad THEN Signal[]};
ScaledText:
PUBLIC
PROC[design:
CD.Design, text:
IO.
ROPE, box:
CD.Position, layer:
CD.Layer]
RETURNS[cell: CD.Object] = {
Scale:
PROC[font: Imager.Font]
RETURNS[scale:
INT] = {
extents: ImagerFont.Extents ← ImagerFont.RopeBoundingBox[font, text];
strSize: CD.Position;
IF box.x<4 OR box.y<4 THEN RETURN[0];
strSize.x ← Real.RoundI[extents.rightExtent+extents.leftExtent];
strSize.y ← Real.RoundI[extents.ascent+extents.descent];
scale ← MIN[box.x/strSize.x, box.y/strSize.y]};
scaleFactor: INT ← Scale[font2];
IF scaleFactor>0
THEN RETURN[CDCreateLabels.CreateTextCell[design, text, font2, scaleFactor, layer]];
scaleFactor ← Scale[font1];
IF scaleFactor>0
THEN RETURN[CDCreateLabels.CreateTextCell[design, text, font1, scaleFactor, layer]];
RETURN[NIL] };
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]]};
BlankCell:
PUBLIC
PROC[design:
CD.Design, size:
CD.Position]
RETURNS[cell:
CD.Object] ~ {
cellPtr: CD.CellPtr;
found: BOOL;
name: ROPE ← IO.PutFR["Dummy-%g-%g", IO.int[size.x], IO.int[size.y]];
IF size.x=0 OR size.y=0 THEN RETURN[NIL];
[found, cell] ← CDDirectory.Fetch[design, name];
IF found THEN RETURN[cell];
cell ← CDCells.CreateEmptyCell[];
cellPtr ← NARROW[cell.specificRef];
cellPtr.contents ←
CONS[
NEW[
CD.InstanceRep ←
[ob: CDRects.CreateRect[size, CD.backGround]] ], cellPtr.contents];
PW.IncludeInDirectory[design, cell, name]};
ShellToBlock:
PUBLIC
PROC[design:
CD.Design, shell:
REF ShellRec]
RETURNS[block: CD.Object] = {
size: CD.Position ← [shell.size.x, shell.size.y];
hor, ver: CD.Object;
box: CD.Position;
text: CD.Object;
layer: CD.Layer;
lineScale: INT = 4 ;
lwidth: INT ← 1;
rotate: BOOL ← FALSE;
IF size.x=0 OR size.y=0 THEN RETURN[NIL];
IF size.x
IN (0..4*lineScale)
OR size.y
IN (0..4*lineScale)
THEN RETURN[BlankCell[design, size]];
lwidth ← lineScale * MAX[lwidth, MIN[size.x/100, size.y/100]];
box ← [(size.x-4*lwidth), (size.y-4*lwidth)];
IF box.y/box.x > 1 THEN {box ← CD.Position[box.y, box.x]; rotate ← TRUE};
layer ←
SELECT design.technology
FROM
CMosB.cmosB => CMosB.met,
CMos.cmos => CMos.met,
CDSil.cdsil => CDSil.xneutral,
ENDCASE => ERROR;
hor ← CDRects.CreateRect[[size.x, lwidth], layer];
ver ← CDRects.CreateRect[[lwidth, size.y], layer];
block ← CDCells.CreateEmptyCell[];
text ← ScaledText[design, shell.name, box, layer];
IF text#
NIL
THEN {
IF rotate THEN text ← PW.Rot90[design, text];
[ ] ← PW.IncludeInCell[block, text, [(size.x-text.size.x)/2, (size.y-text.size.y)/2]]};
[ ] ← PW.IncludeInCell[block, hor, [0, 0]];
[ ] ← PW.IncludeInCell[block, hor, [0, size.y-lwidth]];
[ ] ← PW.IncludeInCell[block, ver, [0, 0]];
[ ] ← PW.IncludeInCell[block, ver, [size.x-lwidth, 0]];
PW.IncludeInDirectory[design, block, shell.name]};
ShellToObject:
PUBLIC
PROC[design:
CD.Design, shell:
REF ShellRec, detailed:
BOOL ←
TRUE]
RETURNS[cell: CD.Object] = {
IF design.technology= CDSil.cdsil
OR
NOT detailed
THEN
RETURN[ShellToBlock[design, shell]];
FOR side: Side
IN Side
DO
IF shell.pins[side]#NIL THEN EXIT
REPEAT FINISHED => RETURN[ShellToBlock[design, shell]] ENDLOOP;
cell ← CDCells.CreateEmptyCell[];
FOR side: Side
IN Side
DO
pins: REF PinSeq ← shell.pins[side];
IF pins#
NIL
THEN
FOR i:
INT
IN [0..pins.seqSize)
DO
pos: CD.Position ← [pins[i].pos.x-shell.pos.x, pins[i].pos.y-shell.pos.y];
pinApl:
CD.Instance ←
PW.IncludeInCell
[cell, CDPinObjects.CreatePinOb[pins[i].size], pos];
CDPinObjects.SetName[pinApl, pins[i].name];
CDPinObjects.SetLayer[pinApl, pins[i].layer] ENDLOOP;
ENDLOOP;
CDCells.SetInterestRect[cell, [0, 0, shell.size.x, shell.size.y]];
PW.IncludeInDirectory[design, cell, shell.name];
IF CD.InterestSize[cell]#[shell.size.x, shell.size.y] THEN Signal[]};
IncludePinNamesInBlock:
PROC
[design: CD.Design, shell: REF ShellRec, block: CD.Object, layer: CD.Layer] = {
textOb: CD.Object;
FOR side: Side
IN Side
DO
pins: REF PinSeq ← shell.pins[side];
bias: INT = 8;
orient:
CD.Orientation ←
SELECT side
FROM
left, right => CDOrient.original,
top, bottom => CDOrient.rotate90,
ENDCASE => ERROR;
IF pins#
NIL
THEN
FOR i:
INT
IN [0..pins.seqSize)
DO
pos: CD.Position;
textOb ← ScaledText[design, pins[i].name, [400, 14], layer];
textOb: CD.Object ← CDTexts.CreateText[pins[i].name, font, layer];
pos.x ←
SELECT side
FROM
left => pins[i].pos.x + bias,
right => pins[i].pos.x + pins[i].size.x - textOb.size.x - bias,
bottom => pins[i].pos.x + pins[i].size.x,
top => pins[i].pos.x + pins[i].size.x,
ENDCASE => ERROR;
pos.y ←
SELECT side
FROM
left => pins[i].pos.y,
right => pins[i].pos.y,
bottom => pins[i].pos.y + bias,
top => pins[i].pos.y + pins[i].size.y - textOb.size.x - bias,
ENDCASE => ERROR;
[ ] ← PW.IncludeInCell[block, textOb, pos, orient];
ENDLOOP
ENDLOOP};
CellInDesign:
PUBLIC
PROC[cell:
CD.Object, design:
CD.Design]
RETURNS[
BOOL]=
{RETURN[cell#NIL AND cell = CDDirectory.Fetch[design, CDDirectory.Name[cell]].object ]};
ExpandFrame:
PUBLIC ExpandProc = {
new ← frame;
IF new=NIL THEN {Signal[]; RETURN[NIL]};
IF new.seqSize > 0
THEN {
FOR index:
INT
IN [0..new.seqSize)
DO
new[index] ← ExpandFrame[new[index], design] ENDLOOP}
ELSE {
IF new.data=NIL THEN {Signal[]; RETURN[new]};
WITH new.data
SELECT
FROM
cell: CD.Object => new.shell ← ShellFromObject[NARROW[new.data]];
shell:
REF ShellRec => {
frame.shell ← shell;
frame.data ← ShellToObject[design, shell, TRUE]};
cellName:
IO.
ROPE => {
cell: CD.Object;
found: BOOL;
[found, cell] ← CDDirectory.Fetch[design, cellName];
IF found
THEN {new.data ← cell; new.shell ← ShellFromObject[cell]}
ELSE {Signal[]; new.shell ← ShellFromFile[cellName]} };
proc:
REF
PROC [design:
CD.Design]
RETURNS [cell:
CD.Object] => {
new.data ← proc^[design];
new.shell ← ShellFromObject[NARROW[new.data]]};
proc:
REF
PW.UserProc => {
new.data ← proc^[design, NIL, NIL, NIL];
new.shell ← ShellFromObject[NARROW[new.data]]};
proc:
REF ExpandProc => {
orient: CD.Orientation ← new.orient;
new ← proc^[new, design];
new ← ExpandFrame[new, design];
new.orient ← orient;
RETURN[new]};
glue:
REF GlueSpec => {
log.PutRope["\n Glue Spec expansion delayed: "];
log.PutRope[new.shell.name]; RETURN[new]};
ENDCASE => {
log.PutRope["\n Unknown expansion delayed: "];
log.PutRope[new.shell.name]; RETURN[new]};
log.PutRope["\n Expanded frame: "];
log.PutRope[new.shell.name];
IF new.shell.size.x <1 OR new.shell.size.y <1 THEN Signal[]};
RETURN[new]};
DeleteZeroFrames:
PUBLIC
PROC[frame: Frame]
RETURNS[new: Frame] = {
IF frame.shell.size.x=0
OR frame.shell.size.y=0
THEN {
log.PutRope["\n Deleteing zero sized frame:%"];
log.PutRope[frame.shell.name];
RETURN[NIL]};
IF frame.seqSize = 0
THEN RETURN[frame]
ELSE {
count: INT ← 0;
FOR index:
INT
IN [0..frame.seqSize)
DO
frame[index] ← DeleteZeroFrames[frame[index]];
IF frame[index]#NIL THEN count ← count+1; ENDLOOP;
IF count = frame.seqSize THEN RETURN[frame];
new ← NEW[FrameSeq[count]];
new.shell ← frame.shell;
new.data ← frame.data;
new.xory ← frame.xory;
new.unordered ← frame.unordered;
FOR index:
INT
DECREASING
IN [0..frame.seqSize)
DO
IF frame[index]=NIL THEN LOOP;
count ← count-1;
new[count] ← frame[index] ENDLOOP;
RETURN[new]}};
ReadShellFrame:
PUBLIC SpecificFrameProc = {
-- new done ← frame name design
IF name=NIL THEN name ← frame.shell.name;
IF frame.shell#
NIL
AND Rope.Equal[frame.shell.name, name]
THEN
{RETURN[NewShellFileFrame[name], TRUE]};
done ← FALSE;
new ← frame;
FOR index:
INT
IN [0..new.seqSize)
WHILE
NOT done
DO
[new[index], done] ← ReadShellFrame[new[index], name, design] ENDLOOP};
WriteShellFrame:
PUBLIC SpecificFrameProc = {
-- new done ← frame name design
IF name=NIL THEN name ← frame.shell.name;
IF frame.shell#
NIL
AND Rope.Equal[frame.shell.name, name]
THEN
{ShellToFile[frame.shell]; RETURN[frame, TRUE]};
done ← FALSE;
new ← frame;
FOR index:
INT
IN [0..new.seqSize)
WHILE
NOT done
DO
[new[index], done] ← WriteShellFrame[new[index], name, design] ENDLOOP};
FrameToObject:
PUBLIC
PROC[frame: Frame, design:
CD.Design, detailed:
BOOL ←
TRUE]
RETURNS[cell: CD.Object] = {
IF design.technology=CMosB.cmosB
AND frame.data#
NIL
AND
ISTYPE[frame.data,
CD.Object]
THEN RETURN[NARROW[frame.data]];
IF frame.seqSize=0
THEN RETURN[ShellToObject[design, frame.shell, detailed]]
ELSE {
list: PW.ListOb;
FOR i:
INT
DECREASING
IN [0..frame.seqSize)
DO
list ← CONS[FrameToObject[ frame.seq[i],design], list] ENDLOOP;
IF frame.xory=x
THEN cell ← PW.AbutListX[design, list]
ELSE cell ← PW.AbutListY[design, list];
PW.RenameObject[design, cell, frame.shell.name]} };
ReOrient:
PUBLIC
PROC
[frame: Frame, design: CD.Design, orient: CD.Orientation ← CD.original] = {
ReSeq:
PROC = {
TwoFrames: TYPE = RECORD[f0, f1: Frame];
FOR i:
INT
IN [0..frame.seqSize/2)
DO
[frame[frame.seqSize-i-1], frame[i]] ← TwoFrames[frame[i], frame[frame.seqSize-i-1]];
ENDLOOP};
yorx: XorY ← IF frame.xory = x THEN y ELSE x;
IF frame.orient#CDOrient.original THEN ERROR;
orient ← CDOrient.ComposeOrient[frame.orient, orient];
frame.orient ← CDOrient.original;
IF frame.seqSize = 0
THEN {
IF orient=CDOrient.original THEN RETURN;
IF frame.data= NIL THEN ERROR;
WITH frame.data
SELECT
FROM
glue:
REF GlueSpec => {
OPEN glue;
type ←
SELECT orient
FROM
CDOrient.original => [type[bottom], type[right], type[top], type[left]],
CDOrient.mirrorX => [type[bottom], type[left], type[top], type[right]],
CDOrient.rotate90 => [type[left], type[bottom], type[right], type[top]],
CDOrient.rotate90X => [type[left], type[top], type[right], type[bottom]],
CDOrient.rotate180 => [type[top], type[left], type[bottom], type[right]],
CDOrient.rotate180X => [type[top], type[right], type[bottom], type[left]],
CDOrient.rotate270 => [type[right], type[top], type[left], type[bottom]],
CDOrient.rotate270X => [type[right], type[bottom], type[left], type[top]],
ENDCASE => ERROR;
obj ←
SELECT orient
FROM
CDOrient.original => [obj[bottom], obj[right], obj[top], obj[left]],
CDOrient.mirrorX => [obj[bottom], obj[left], obj[top], obj[right]],
CDOrient.rotate90 => [obj[left], obj[bottom], obj[right], obj[top]],
CDOrient.rotate90X => [obj[left], obj[top], obj[right], obj[bottom]],
CDOrient.rotate180 => [obj[top], obj[left], obj[bottom], obj[right]],
CDOrient.rotate180X => [obj[top], obj[right], obj[bottom], obj[left]],
CDOrient.rotate270 => [obj[right], obj[top], obj[left], obj[bottom]],
CDOrient.rotate270X => [obj[right], obj[bottom], obj[left], obj[top]],
ENDCASE => ERROR;
FOR side: Side
IN Side
DO
IF obj[side]#
NIL
AND type[side]=chan
THEN obj[side] ← PW.ChangeOrientation[design, obj[side], orient]
ELSE obj[side] ← NIL ENDLOOP;
SELECT orient
FROM
CDOrient.rotate90,
CDOrient.rotate90X,
CDOrient.rotate270,
CDOrient.rotate270X => {
temp: IO.ROPE ← params.branchLayer;
params.branchLayer ← params.trunkLayer;
params.trunkLayer ← temp;
frame.shell.size ← FlipSize[frame.shell.size];
tDir ← IF tDir=horizontal THEN vertical ELSE horizontal};
ENDCASE };
cell:
CD.Object => {
cell ← PW.ChangeOrientation[design, cell, orient];
frame.shell.size ← FixedSize[CD.InterestSize[cell]];
frame.data ← cell};
ENDCASE => ERROR;
RETURN};
SELECT orient
FROM
CDOrient.original => { };
CDOrient.mirrorX => { IF frame.xory=x THEN ReSeq[] };
CDOrient.rotate90 => {frame.xory ← yorx; IF frame.xory=x THEN ReSeq[] };
CDOrient.rotate90X => {frame.xory ← yorx; };
CDOrient.rotate180 => { IF TRUE THEN ReSeq[] };
CDOrient.rotate180X => { IF frame.xory=y THEN ReSeq[] };
CDOrient.rotate270 => {frame.xory ← yorx; IF frame.xory=y THEN ReSeq[] };
CDOrient.rotate270X => {frame.xory ← yorx; IF TRUE THEN ReSeq[] };
ENDCASE;
FOR i: INT IN [0..frame.seqSize) DO ReOrient[frame[i], design, orient] ENDLOOP};
ObjSize:
PUBLIC
PROC[ob:
CD.Object]
RETURNS[size:
CD.Position] =
{RETURN[CD.InterestSize[ob]]};
GetSize:
PUBLIC
PROC[frame: Frame] = {
variable: BOOL ← FALSE;
dad, son: Size;
IF frame.seqSize = 0
THEN {
IF frame.data=NIL THEN {Signal[]; RETURN};
WITH frame.data
SELECT
FROM
cell: CD.Object => {frame.shell.size ← FixedSize[CD.InterestSize[cell]]};
glue:
REF GlueSpec => {
frame.shell.size ← TameSize[];
IF glue.class=chan
OR glue.class=pwr
THEN
IF glue.tDir=vertical
THEN frame.shell.size.xfree ← wild
ELSE frame.shell.size.yfree ← wild};
ENDCASE => ERROR;
IF frame.shell.size.x < 1 OR frame.shell.size.y < 1 THEN {Signal[]; frame.data ← NIL};
RETURN};
dad ← [0, 0, fixed, tame];
FOR i:
INT
IN [0..frame.seqSize)
DO
--
Normalize sons to x sequences for computations
GetSize[frame.seq[i]];
son ← IF frame.xory=y THEN FlipSize[frame.seq[i].shell.size] ELSE frame.seq[i].shell.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.seqSize)
DO
son ← IF frame.xory=y THEN FlipSize[frame.seq[i].shell.size] ELSE frame.seq[i].shell.size;
IF dad.yfree=fixed
AND son.yfree=wild
THEN {
log.PutF["\n WARNING: Limited wild %g width%g\n",
IO.rope[ IF frame.xory=x THEN "Y" ELSE "X" ],
IO.rope[ ListFrame[frame, 2] ] ]; EXIT};
ENDLOOP;
frame.shell.size ← IF frame.xory=y THEN FlipSize[dad] ELSE dad};
CheckXSeqForExpansionError:
PROC[size1, size2: Size, frame: Frame] = {
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[frame.shell.name]];
log.PutRope[ListFrame[frame.father, 2]];
log.Flush[];
Signal[]} };
PutSize:
PUBLIC
PROC[frame: Frame] = {
dad, son: Size;
freedom: Freedom;
oneVariable: BOOL;
cnt: ARRAY Freedom OF INT ← ALL[0];
length, diff: INT ← 0;
IF frame.seqSize = 0 THEN RETURN;
dad ← IF frame.xory=y THEN FlipSize[frame.shell.size] ELSE frame.shell.size; -- norm
FOR ii:
INT
IN [0..frame.seqSize)
DO
son ← frame.seq[ii].shell.size;
son ← IF frame.xory=y THEN FlipSize[son] ELSE 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 frame.xory=x 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 [frame[ii].shell.name] ];
frame.seq[ii].shell.size ← IF frame.xory=y THEN FlipSize[son] ELSE 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.seqSize)
WHILE cnt[freedom] > 0
DO
incr: INT ← diff/cnt[freedom];
son ← frame.seq[ii].shell.size;
son ← IF frame.xory=y THEN FlipSize[son] ELSE son; -- norm;
IF son.xfree#freedom THEN LOOP;
log.PutF["\n %g length changed from %6g %6g",
IO.rope[IF frame.xory=x 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 [frame[ii].shell.name] ];
diff ← diff - incr;
cnt[freedom] ← cnt[freedom] - 1;
frame.seq[ii].shell.size ← IF frame.xory=y THEN FlipSize[son] ELSE son; -- denorm
ENDLOOP;
IF diff#0 THEN ERROR};
FOR i: INT IN [0..frame.seqSize) DO PutSize[frame.seq[i]] ENDLOOP };
Signal: SIGNAL = CODE;
PutPos:
PUBLIC
PROC[frame: Frame, new:
CD.Position] = {
cng: CD.Position ← [new.x-frame.shell.pos.x, new.y-frame.shell.pos.y];
pos: CD.Position ← frame.shell.pos ← new;
IF frame.seqSize=0
THEN {
FOR side: Side
IN Side
DO
IF frame.shell.pins[side]=
NIL
THEN LOOP
ELSE
FOR pin:
INT
IN [0..frame.shell.pins[side].seqSize)
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.seqSize)
DO
PutPos[frame.seq[i], pos];
SELECT frame.xory
FROM
x => pos.x ← pos.x + frame.seq[i].shell.size.x;
y => pos.y ← pos.y + frame.seq[i].shell.size.y;
ENDCASE ENDLOOP };
GetPins:
PUBLIC
PROC[frame: Frame] = {
Merge:
PROC[pins1, pins2:
REF PinSeq]
RETURNS[pins:
REF PinSeq] = {
pins ← NEW[PinSeq[pins1.seqSize+(IF pins2=NIL THEN 0 ELSE pins2.seqSize)]];
pins.locInfo ← MIN[pins1.locInfo, (IF pins2=NIL THEN unk ELSE pins2.locInfo)];
FOR i:INT IN [0..pins1.seqSize) DO pins[i ] ← pins1[i] ENDLOOP;
IF pins2=NIL THEN RETURN[pins];
FOR i:INT IN [0..pins2.seqSize) DO pins[i+pins1.seqSize ] ← pins2[i] ENDLOOP };
pins: ARRAY Side OF REF PinSeq;
IF frame.seqSize = 0 THEN RETURN;
IF frame.seqSize = 0 THEN {
FOR side: Side IN Side DO
bias: INT ← SELECT side FROM
top, bottom => frame.shell.pos.x,
ENDCASE => frame.shell.pos.y;
IF frame.shell.pins[side]=NIL
THEN LOOP
ELSE IF frame.shell.pins[side].locInfo=fixed THEN
FOR pin: INT IN [0..frame.shell.pins[side].seqSize) DO
pos: INT ← GetSidePos[frame.shell.pins[side][pin]];
IF pos = unk THEN ERROR;
SetSidePos[frame.shell.pins[side][pin], pos + bias];
ENDLOOP
ENDLOOP;
RETURN};
FOR side: Side
IN Side
DO
pins[side] ← NEW[PinSeq[0]]; pins[side].locInfo ← fixed ENDLOOP;
FOR i:
INT
IN [0..frame.seqSize)
DO
GetPins[frame.seq[i]];
SELECT frame.xory
FROM
x => {
pins[top] ← Merge[pins[top], frame.seq[i].shell.pins[top]];
pins[bottom] ← Merge[pins[bottom], frame.seq[i].shell.pins[bottom]]};
y => {
pins[right] ← Merge[pins[right], frame.seq[i].shell.pins[right]];
pins[left] ← Merge[pins[left], frame.seq[i].shell.pins[left]]};
ENDCASE;
ENDLOOP;
SELECT frame.xory
FROM
x => {
pins[right] ← Merge[pins[right], frame.seq[frame.seqSize-1 ].shell.pins[right]];
pins[left] ← Merge[pins[left], frame.seq[0 ].shell.pins[left]]};
y => {
pins[top] ← Merge[pins[top], frame.seq[frame.seqSize-1 ].shell.pins[top]];
pins[bottom] ← Merge[pins[bottom], frame.seq[0 ].shell.pins[bottom]]};
ENDCASE;
frame.shell.pins ← pins};
FixOneSize:
PUBLIC
PROC [frame: Frame]
RETURNS[fixed1:
BOOL ←
FALSE] = {
FixOneSizeRecursive:
PUBLIC
PROC [fframe: Frame]
RETURNS[ffixed1:
BOOL ←
FALSE] = {
lastTame: INT ← -1;
wildOrMultTamesFound: BOOL ← FALSE;
FOR kid:
INT
IN [0..fframe.seqSize)
DO
SELECT (
IF fframe.xory=x
THEN fframe[kid].shell.size.xfree
ELSE fframe[kid].shell.size.yfree)
FROM
fixed => LOOP;
wild => wildOrMultTamesFound ← TRUE;
ENDCASE => {IF lastTame#-1 THEN wildOrMultTamesFound ← TRUE; lastTame←kid};
ENDLOOP;
IF lastTame#-1
AND wildOrMultTamesFound
THEN {
IF fframe.xory=x
THEN {fframe[lastTame].shell.size.xfree ← fixed; log.PutRope["\n X length"]}
ELSE {fframe[lastTame].shell.size.yfree ← fixed; log.PutRope["\n Y length"]};
log.PutF[" FIXED in %g", IO.rope[fframe[lastTame].shell.name]];
PutSize[fframe]; RETURN[TRUE]};
FOR kid:
INT
IN [0..fframe.seqSize)
WHILE
NOT ffixed1
DO ffixed1 ← FixOneSizeRecursive[fframe[kid]] ENDLOOP};
IF FixOneSizeRecursive[frame] THEN RETURN[TRUE];
IF frame.shell.size.xfree=tame
THEN {frame.shell.size.xfree𡤏ixed; PutSize[frame]; RETURN[TRUE]};
IF frame.shell.size.yfree=tame
THEN {frame.shell.size.yfree𡤏ixed; PutSize[frame]; RETURN[TRUE]};
RETURN[FALSE]};
TellKidsAboutDad:
PUBLIC
PROC [dad: Frame] = {
FOR kid:
INT
IN [0..dad.seqSize)
DO dad[kid].father ← dad; TellKidsAboutDad[dad[kid]] ENDLOOP};
Neighbor:
PUBLIC
PROC [leaf: Frame, side: Side]
RETURNS[neighbor: Frame, ok: BOOL] = {
NeighborCheck:
PROC[frame: Frame]
RETURNS[type: {eq, ok, out}] = {
negh: CD.Rect ← CDBasics.RectAt[frame.shell.pos, [frame.shell.size.x,frame.shell.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 };
neighborSide: Side ← OppSide[side];
seg: CD.Rect ← CDBasics.RectAt[leaf.shell.pos, [leaf.shell.size.x,leaf.shell.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 neighbor ← leaf.father, neighbor.father
WHILE neighbor#
NIL
DO
SELECT NeighborCheck[neighbor]
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[leaf.shell.name]];
RETURN[NIL, FALSE]} ENDLOOP;
DO
IF neighbor.seqSize=0 THEN RETURN[neighbor, FALSE];
FOR i:
INT
IN [0..neighbor.seqSize)
DO
SELECT NeighborCheck[neighbor[i]]
FROM
out => LOOP;
eq => {neighbor ← neighbor[i]; GOTO Found};
ENDCASE => {neighbor ← neighbor[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[leaf.shell.name]];
RETURN[NIL, FALSE]} ENDLOOP;
ENDLOOP;
RETURN[neighbor, TRUE]};
FixImpliedPins: PROC[frame: REF FrameRec] = {
IF frame.seq # NIL
THEN FOR i: INT IN [0..frame.seq.seqSize-1) DO {
aSide: Side ← IF frame.seq.xory = x THEN right ELSE top;
bSide: Side ← IF frame.seq.xory = x THEN left ELSE bottom;
aPins: REF PinSeq ← frame.seq[i+0].shell.pins[aSide];
bPins: REF PinSeq ← frame.seq[i+1].shell.pins[bSide];
FOR aPin: INT IN [0..aPins.seqSize) DO
IF aPins[aPin].pos#unk THEN LOOP;
FOR bPin: INT IN [0..bPins.seqSize) DO
IF ~Rope.Equal[bPins[bPin].name, aPins[aPin].name] THEN LOOP;
IF bPins[bPin].pos=unk THEN ERROR;
aPins[aPin].pos ← bPins[bPin].pos;
IF aPins[aPin].size=unkSize THEN aPins[aPin].size ← bPins[bPin].size;
EXIT REPEAT FINISHED => ERROR ENDLOOP;
FOR bPin: INT IN [0..bPins.seqSize) DO
IF bPins[bPin].pos#unk THEN LOOP;
FOR aPin: INT IN [0..aPins.seqSize) DO
IF ~Rope.Equal[aPins[aPin].name, bPins[bPin].name] THEN LOOP;
IF aPins[aPin].pos=unk THEN ERROR;
bPins[bPin].pos ← aPins[aPin].pos;
IF bPins[bPin].size=unkSize THEN bPins[bPin].size ← aPins[aPin].size;
EXIT REPEAT FINISHED => ERROR ENDLOOP;
IF bPins.seqSize# aPins.seqSize THEN ERROR;
SORT both ?
Checkd that newly defined pins are still in range of cells
FOR pin: INT IN [0..aPins.seqSize) DO
IF ~Rope.Equal[aPins[pin].name, bPins[pin].name] THEN ERROR;
IF aPins[pin].pos#bPins[pin].pos THEN ERROR ENDLOOP };
FreeRope: ARRAY Freedom OF IO.ROPE ← ["fixed", "tame", "wild"];
ListFrame:
PUBLIC
PROC[frame: Frame, limit:
INT ← -1]
RETURNS[listing:
IO.
ROPE] = {
out: IO.STREAM ← IO.ROS[];
LogFrame[frame, limit, out];
listing ← IO.RopeFromROS[out]};
LogFrame:
PUBLIC
PROC[frame: Frame, limit:
INT ← -1, out:
IO.
STREAM ←
NIL] = {
Gauge:
PROC[fframe: Frame, depth:
INT] = {
requiredOffset ← MAX[requiredOffset, depth+fframe.shell.name.Length[]];
FOR i: INT IN [0..fframe.seqSize) DO Gauge[fframe.seq[i], depth+1] ENDLOOP};
ListF:
PROC[fframe: Frame, depth:
INT] = {
name: IO.ROPE ← namerame.shell.name;
size: Size ← fframe.shell.size;
pos: CD.Position ← fframe.shell.pos;
IF depth=limit THEN RETURN;
out.PutRope["\n"];
FOR i: INT IN [0..depth) DO out.PutRope[" "] ENDLOOP;
out.PutRope[name];
THROUGH [name.Length[]+depth..requiredOffset) DO out.PutRope[" "] ENDLOOP;
out.PutF[" %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[" %8g%8g", IO.int[pos.x], IO.int[pos.y] ];
IF fframe.seqSize#0
THEN
IF fframe.xory=x
THEN out.PutRope[" x seq"]
ELSE out.PutRope[" y seq"];
IF fframe.unordered THEN out.PutRope[" ~"];
FOR i: INT DECREASING IN [0..fframe.seqSize) DO ListF[fframe.seq[i], depth+1] ENDLOOP};
requiredOffset: INT ← 0;
IF out=NIL THEN out ← GetLog[];
Gauge[frame,0];
ListF[frame, 0]};
FullFrameName:
PUBLIC
PROC[frame: Frame]
RETURNS[name:
IO.
ROPE] = {
FOR temp: Frame ← frame.father, temp.father
WHILE temp#
NIL
DO
name ← Rope.Cat[temp.shell.name, ".", name] ENDLOOP;
name ← name.Cat[frame.shell.name]};
FlattenOnce:
PUBLIC
PROC[frame: Frame]
RETURNS[new: Frame] =
{new ← TestMergeNodes[frame]};
TestMergeNodes:
PUBLIC
PROC[frame: Frame, 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.seqSize)
DO
IF testProc=
NIL
OR testProc[frame[index]]
THEN {
IF xory#frame[index].xory THEN ERROR;
FOR element:
CARDINAL
IN [0..frame[index].seqSize)
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.shell.name, frame.data, frame.unordered];
FOR node:
CARDINAL
DECREASING
IN [0..new.seqSize)
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].seqSize)
DO new[node][element] ← list.first; list ← list.rest ENDLOOP};
plaFrame: Frame => {new[node] ← plaFrame};
ENDCASE => ERROR;
nlist ← nlist.rest ENDLOOP};
EnumFrameTopFirst:
PUBLIC
PROC[frame: Frame, proc: EnumProc] = {
proc[frame];
FOR field:
INT
IN [0..frame.seqSize)
DO EnumFrameTopFirst[frame[field], proc] ENDLOOP };
EnumFrameBotFirst:
PUBLIC
PROC[frame: Frame, proc: EnumProc] = {
FOR field:
INT
IN [0..frame.seqSize)
DO EnumFrameBotFirst[frame[field], proc] ENDLOOP;
proc[frame] };
EnumFrameBotOnly:
PUBLIC
PROC[frame: Frame, proc: EnumProc] = {
IF frame.seqSize=0
THEN proc[frame]
ELSE
FOR field:
INT
IN [0..frame.seqSize)
DO EnumFrameBotOnly[frame[field],proc] ENDLOOP};
Shell Stuff
Key: TYPE = REF INT;
ROPE: TYPE = IO.ROPE;
WriteFrameShellFile:
PROC [comm: CDSequencer.Command] = {
inst: CD.Instance ← CDCommandOps.TheInstance[comm: comm, text: "Shell to File "];
IF inst#
NIL
THEN {
log.PutRope[CDOps.Info[inst.ob]];
IF ~CDCells.IsCell[inst.ob]
THEN log.PutRope[" is not a cell\n"]
ELSE {
shell: REF ShellRec;
shellFile: REF ROPE ← NEW[ROPE ← comm.design.name.Cat[".shell"]];
IF comm.data#
NIL
THEN shellFile ← NARROW[comm.data]
ELSE {
log.PutRope["\n"];
shellFile ← NEW[ROPE ← TerminalIO.RequestRope["File name for shell: "]]};
shell ← ShellFromObject[inst.ob];
ShellToFile[shell] } } };
WriteFrameShellFileCT: Commander.CommandProc = {
shell: REF ShellRec;
file: ROPE ← CommandTool.NextArgument[cmd];
IF file=NIL THEN RETURN;
shell ← ShellFromDesign[file];
ShellToFile[shell]};
ShellFromDesign:
PUBLIC
PROC[design:
REF]
RETURNS [shell:
REF ShellRec] = {
IF design#
NIL
AND
ISTYPE[design,
IO.
ROPE]
THEN design ← CDIO.ReadDesign[NARROW[design]];
shell ← ShellFromObject[ObjectFromDesign[NARROW[design]]]};
ObjectFromDesign:
PROC[design:
CD.Design]
RETURNS [cell:
CD.Object] = {
multiple: BOOL;
inst: CD.Instance;
CDSimpleOps.Select[design, [0,0]];
[inst, multiple] ← CDOps.SelectedInstance[design];
IF multiple THEN ERROR;
IF inst=NIL THEN log.PutRope["\n Shell from design . . . no cell at [0, 0]\n"];
IF inst#
NIL
THEN {
log.PutF["\nShell from cell: %g", IO.rope[CDOps.Info[inst.ob]]];
IF ~CDCells.IsCell[inst.ob]
THEN log.PutRope[" is not a cell\n"]
ELSE RETURN[inst.ob] } };
ShellFromObject:
PUBLIC
PROC[cell:
CD.Object]
RETURNS [shell: REF ShellRec] = {
DuplicatePinError: BOOL←FALSE;
AddPinEntry: PWPins.InstanceEnumerator = {
data:
REF PinRec ←
NEW[PinRec ← [
name: CDPinObjects.GetName[inst],
side: PWPins.GetSide[cell, inst].side,
size: inst.ob.size,
pos: inst.location,
layer: CDPinObjects.GetLayer[inst] ] ];
olddata: RedBlackTree.Node ← RedBlackTree.LookupNode[tables[data.side], GetKey[data]];
IF olddata#
NIL
THEN {
oldPin: REF PinRec ← NARROW[olddata.data];
IF
NOT DuplicatePinError
OR NOT (Rope.Equal[oldPin.name, "VDD"] OR Rope.Equal[oldPin.name, "GND"])
OR
NOT (Rope.Equal[oldPin.name, data.name])
THEN log.PutF[ "\n\n Duplicate Pin ERRORs:%g%g\n",
IO.rope[ PinRope[ oldPin, [0,0] ] ], IO.rope[PinRope[data, [0,0]] ] ];
DuplicatePinError ← TRUE;
RETURN};
RedBlackTree.Insert[tables[data.side], data, GetKey[data]];
cnt[data.side] ← cnt[data.side]+1};
SeqTable:
PROC [userdata: RedBlackTree.UserData]
RETURNS [stop:
BOOL ←
FALSE] = {
data: REF PinRec ← NARROW[userdata];
shell.pins[data.side][index] ← data;
index ← index+1};
tables: ARRAY Side OF RedBlackTree.Table;
cnt: ARRAY Side OF INT ← ALL[0];
index: INT;
FOR currentSide: Side
IN Side
DO
tables[currentSide] ← RedBlackTree.Create[getKey: GetKey, compare: Compare] ENDLOOP;
[] ← PWPins.EnumerateEdgePins[cell, AddPinEntry];
shell ← NEW[ShellRec ← [ ]];
shell.name ← CDDirectory.Name[cell];
shell.size ← FixedSize[CD.InterestSize[cell]];
FOR currentSide: Side
IN Side
DO
shell.pins[currentSide] ← NEW[PinSeq[cnt[currentSide]]];
index ← 0;
RedBlackTree.EnumerateIncreasing[tables[currentSide], SeqTable] ENDLOOP };
SideRope: PUBLIC ARRAY Side OF ROPE ← ["BOTTOM", "RIGHT", "TOP", "LEFT"];
ShellFromFile:
PUBLIC
PROC [shellName:
ROPE]
RETURNS [shell:
REF ShellRec] = {
tbp:
IO.BreakProc = {
RETURN[
SELECT char
FROM
IN [IO.NUL .. IO.SP], ',, ':, '; => sepr,
'[, '], '(, '), '{, '}, '", '+, '-, '*, '/, '@, '← => break,
ENDCASE => other]};
shellFile: ROPE ← shellName.Cat[".shell"];
in: IO.STREAM;
cnt: ARRAY Side OF INT ← ALL[0];
pins: ARRAY Side OF LIST OF REF PinRec ← ALL[NIL];
shell ← NEW[ShellRec ← [name: shellName]];
in ← FS.StreamOpen[shellFile ! FS.Error => {in←NIL; CONTINUE}];
IF in=NIL THEN RETURN[shell];
shell.name ← IO.GetTokenRope[in].token;
[ ] ← IO.GetTime[in];
shell.size.x ← IO.GetInt[in];
shell.size.y ← IO.GetInt[in];
shell.size.xfree ← fixed;
shell.size.yfree ← fixed;
DO
name: ROPE ← IO.GetTokenRope[in, tbp ! IO.EndOfStream => EXIT].token;
sideR: ROPE ← IO.GetTokenRope[in].token;
posX: INT ← IO.GetInt[in];
posY: INT ← IO.GetInt[in];
sizeX: INT ← IO.GetInt[in];
sizeY: INT ← IO.GetInt[in];
layer: CD.Layer ← IO.GetInt[in];
data:
REF PinRec ←
NEW[PinRec ← [
name: name,
side: bottom,
pos: [posX, posY],
size: [sizeX, sizeY],
layer: LOOPHOLE[layer] ] ];
FOR test: Side
IN Side
DO
IF Rope.Equal[sideR, SideRope[test]] THEN {data.side ← test; EXIT};
REPEAT FINISHED => ERROR ENDLOOP;
cnt[data.side] ← cnt[data.side] + 1;
pins[data.side] ← CONS[data, pins[data.side] ] ENDLOOP;
in.Close[];
FOR side: Side
IN Side
DO
shell.pins[side] ← NEW[PinSeq[cnt[side]]];
FOR pin:
INT
DECREASING
IN [0..shell.pins[side].seqSize)
DO
shell.pins[side][pin] ← pins[side].first; pins[side] ← pins[side].rest ENDLOOP ENDLOOP };
PinRope:
PROC[pin:
REF PinRec, base:
CD.Position]
RETURNS[rope:
ROPE] = {
out: IO.STREAM ← IO.ROS[];
out.PutF["\n%g %-6g",
IO.rope[pin.name],
IO.rope[SideRope[pin.side]]];
out.PutF["%6g%6g%6g%6g%6g",
IO.int[pin.pos.x-base.x],
IO.int[pin.pos.y-base.y],
IO.int[pin.size.x],
IO.int[pin.size.y],
IO.int[pin.layer]];
RETURN[ IO.RopeFromROS[out] ]};
ShellToFile:
PUBLIC
PROC[shell:
REF ShellRec] = {
shellFile: ROPE ← shell.name.Cat[".shell"];
tabStop45LookF: ROPE = "45 sp tabStops look.f";
node: TextNode.Ref;
out: IO.STREAM ← FS.StreamOpen[shellFile, $create];
log.PutF["\n Writing pin file: %g . . . ", IO.rope[shellFile]];
out.PutF["%g %18g%6g%6g\n",
IO.rope[shell.name],
IO.time[],
IO.int[shell.size.x],
IO.int[shell.size.y]];
FOR side: Side
IN Side
DO
FOR i:
INT
IN [0..shell.pins[side].seqSize)
DO
out.PutRope[ PinRope[shell.pins[side][i], shell.pos]] ENDLOOP ENDLOOP;
out.PutRope["\n"];
out.Close[];
node ← PutGet.FromFile[shellFile];
NodeProps.PutProp[node.child, $Postfix, tabStop45LookF];
[ ] ← PutGet.ToFile[shellFile, node];
log.PutRope[" done\n"]};
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]};
GetSidePos:
PUBLIC
PROC [pin:
REF PinRec]
RETURNS [
INT] =
{RETURN[SELECT pin.side FROM left, right => pin.pos.y, ENDCASE => pin.pos.x]};
SetSidePos:
PUBLIC
PROC [pin:
REF PinRec, pos:
INT] =
{SELECT pin.side FROM left, right => pin.pos.y←pos ENDCASE => pin.pos.x←pos};
REFToINT:
PROC [ref:
REF]
RETURNS [
INT] =
{pin: REF PinRec ← NARROW[ref]; RETURN[GetSidePos[pin]*CD.layerNum + pin.layer]};
GetKey:
PROC [userdata: RedBlackTree.UserData]
RETURNS [RedBlackTree.Key] =
{RETURN[userdata]};
Compare:
PROC [k: RedBlackTree.Key, data: RedBlackTree.UserData]
RETURNS [Basics.Comparison] =
{RETURN[Basics.CompareINT[REFToINT[k], REFToINT[data]]]};
log: IO.STREAM ← NIL;
GetLog:
PUBLIC
PROC
RETURNS[
IO.
STREAM] = {
logName: IO.ROPE ← "CDFrame.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]};
Commander.Register[proc: WriteFrameShellFileCT, key: "CDFrameShell"];
CDSequencer.ImplementCommand[a: $FrameShell, p: WriteFrameShellFile];
CDMenus.CreateEntry[$CellMenu, "Write frame shell file", $FrameShell];
[ ] ← GetLog[];
TerminalIO.WriteRope["FrameShell program loaded\n"];
END.