DIRECTORY
Basics USING [CompareINT, Comparison],
CD,
CDBasics,
CDCells USING [IsCell],
CDCommandOps USING [TheInstance],
CDDirectory,
CDFrame,
CDIO,
CDMenus USING [CreateEntry],
CDOps USING [Info, SelectedInstance],
CDPinObjects USING [GetLayer, GetName],
CDSequencer USING [Command, ImplementCommand],
CDSimpleOps USING [Select],
Commander,
CommandTool,
FS,
IO,
NodeProps USING [PutProp],
PutGet USING [FromFile, ToFile],
PWPins,
RedBlackTree,
Rope USING [Cat, Equal, ROPE],
TerminalIO USING [RequestRope, WriteRope],
TextNode USING [Ref];
CDFrameShell:
CEDAR
PROGRAM
IMPORTS Basics, CD, CDBasics, CDCells, CDCommandOps, CDDirectory, CDIO, CDMenus, CDOps, CDPinObjects, CDSequencer, CDSimpleOps, Commander, CommandTool, IO, FS, NodeProps, PWPins, PutGet, RedBlackTree, Rope, TerminalIO
EXPORTS CDFrame =
BEGIN OPEN CDFrame;
Key: TYPE = REF INT;
ROPE: TYPE = Rope.ROPE;
WriteFrameShellFile:
PROC [comm: CDSequencer.Command] = {
inst: CD.Instance ← CDCommandOps.TheInstance[comm: comm, text: "Shell to File "];
IF inst#
NIL
THEN {
TerminalIO.WriteRope[CDOps.Info[inst.ob]];
IF ~CDCells.IsCell[inst.ob]
THEN TerminalIO.WriteRope[" 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 {
TerminalIO.WriteRope["\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, Rope.
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 TerminalIO.WriteRope["\nShell from design . . . no cell at [0, 0]\n"];
IF inst#
NIL
THEN {
TerminalIO.WriteRope["\nShell from cell: "];
TerminalIO.WriteRope[CDOps.Info[inst.ob]];
IF ~CDCells.IsCell[inst.ob]
THEN TerminalIO.WriteRope[" is not a cell\n"]
ELSE RETURN[inst.ob] } };
ShellFromObject:
PUBLIC
PROC[cell:
CD.Object]
RETURNS [shell: REF ShellRec] = {
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 {
TerminalIO.WriteRope["\n Duplicate Pins:"];
TerminalIO.WriteRope[ PinRope[NARROW[olddata.data]]];
TerminalIO.WriteRope[ PinRope[data]];
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 ← CDBasics.SizeOfRect[CD.InterestRect[cell]];
FOR currentSide: Side
IN Side
DO
shell.pins[currentSide] ← NEW[PinSeq[cnt[currentSide]]];
index ← 0;
RedBlackTree.EnumerateIncreasing[tables[currentSide], SeqTable] ENDLOOP };
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];
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];
side: Side ←
SELECT
TRUE
FROM
Rope.Equal[sideR, "LEFT"] => left,
Rope.Equal[sideR, "RIGHT"] => right,
Rope.Equal[sideR, "TOP"] => top,
Rope.Equal[sideR, "BOTTOM"] => bottom,
ENDCASE => ERROR;
data:
REF PinRec ←
NEW[PinRec ← [
name: name,
side: side,
pos: [posX, posY],
size: [sizeX, sizeY],
layer: LOOPHOLE[layer] ] ];
cnt[side] ← cnt[side] + 1;
pins[side] ← CONS[data, pins[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]
RETURNS[rope:
ROPE] = {
out: IO.STREAM ← IO.ROS[];
sideRope:
ROPE ←
SELECT pin.side
FROM
left => "LEFT ",
right => "RIGHT ",
top => "TOP ",
bottom => "BOTTOM",
ENDCASE => ERROR;
out.PutF["\n%g %6g",
IO.rope[pin.name],
IO.rope[sideRope]];
out.PutF["%6g%6g%6g%6g%6g",
IO.int[pin.pos.x],
IO.int[pin.pos.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];
TerminalIO.WriteRope["\nWriting pin file: "];
TerminalIO.WriteRope[shellFile];
TerminalIO.WriteRope[" . . . "];
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]]] ENDLOOP ENDLOOP;
out.PutRope["\n"];
out.Close[];
node ← PutGet.FromFile[shellFile];
NodeProps.PutProp[node.child, $Postfix, tabStop45LookF];
[ ] ← PutGet.ToFile[shellFile, node];
TerminalIO.WriteRope[" done\n"]};
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};
NewFrame:
PUBLIC
PROC
[size:
INT, xory: XorY, name: Rope.
ROPE, data:
REF←
NIL, unord:
BOOL←
FALSE]
RETURNS [new:
REF FrameSeq] = {
new ← NEW[FrameSeq[size]];
new.xory ← xory;
new.data ← data;
new.unordered ← unord;
new.shell ← NEW[ShellRec ← [name: name]] };
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]]]};
Commander.Register[proc: WriteFrameShellFileCT, key: "CDFrameShell"];
CDSequencer.ImplementCommand[a: $FrameShell, p: WriteFrameShellFile];
CDMenus.CreateEntry[$CellMenu, "Write frame shell file", $FrameShell];
TerminalIO.WriteRope["FrameShell program loaded\n"];
END.