CDExtrasImpl.mesa (part of ChipNDale)
Copyright © 1983, 1985 by Xerox Corporation. All rights reserved.
by Christian Jacobi, September 8, 1983 9:45 am
last edited by Christian Jacobi, June 29, 1985 5:38:05 pm PDT
DIRECTORY
Atom,
CD,
CDBasics,
CDCells,
CDDirectory,
CDExtras,
CDInstances,
CDOps,
CDPrivate,
CDProperties,
CDSimpleOps,
CedarProcess,
IO,
Process,
Rope,
SymTab,
TerminalIO;
CDExtrasImpl: CEDAR MONITOR
IMPORTS Atom, CD, CDBasics, CDCells, CDDirectory, CDInstances, CDOps, CDProperties, CDSimpleOps, CedarProcess, IO, Process, Rope, SymTab, TerminalIO
EXPORTS CDExtras
SHARES CD =
BEGIN
CreateDummyObject: PUBLIC PROC[design: CD.Design] RETURNS [CD.Object] =
--create a dummy cell object which contains the whole design.
--On future changes of the design, the dummy object may or may not
--get obsolete.
BEGIN
cellOb: CD.Object ← CDCells.CreateEmptyCell[];
cptr: CD.CellPtr ← NARROW[cellOb.specificRef];
FOR l: LIST OF CD.PushRec ← design.actual, l.rest WHILE l#NIL DO
cptr.contents ← CONS[
NEW[CD.InstanceRep ← [
ob: l.first.dummyCell.ob,
location: [0, 0],
orientation: CD.original,
selected: FALSE
]],
cptr.contents
];
ENDLOOP;
RETURN [cellOb]
END;
Pair: TYPE = RECORD [p: CDDirectory.EnumerateObjectsProc, x: REF, key: REF];
EnumerationEnteredWhileInProgress: ERROR = CODE;
entered: BOOLFALSE;
Enter: ENTRY PROC [] =
BEGIN
IF entered THEN RETURN WITH ERROR EnumerationEnteredWhileInProgress;
entered←TRUE;
END;
Leave: ENTRY PROC [] =
BEGIN
entered←FALSE;
END;
EnumerateChildrenObjects: PUBLIC PROC[me: CD.Object, p: CDDirectory.EnumerateObjectsProc, x: REF] =
--enumerate me and its children objects
BEGIN ENABLE UNWIND => Leave[];
pair: REF Pair ← NEW[Pair];
pair^ ← [p, x, pair];
Enter[];
MyEnum[me, pair];
Leave[];
END;
MyEnum: PROC [me: CD.Object, x: REF] =
BEGIN
pair: REF Pair ← NARROW[x];
v: REF ← Atom.GetPropFromList[me.properties, $CDExtrasImplsTouched];
IF v=pair.key THEN RETURN; -- already visited
--mark visited
me.properties ← Atom.PutPropOnList[me.properties, $CDExtrasImplsTouched, pair.key];
--enumerate my children first
IF me.class.inDirectory THEN CDDirectory.EnumerateChildObjects[me, MyEnum, x];
pair.p[me, pair.x]; -- call clients enumerator proc
END;
EnumerateDesignObjects: PUBLIC PROC [design: CD.Design, p: CDDirectory.EnumerateObjectsProc, x: REF] =
BEGIN ENABLE UNWIND => Leave[];
pair: REF Pair ← NEW[Pair];
EachCell: SymTab.EachPairAction --[key: Key, val: Val] RETURNS [quit: BOOLEAN] -- =
BEGIN
quit ← FALSE;
MyEnum[NARROW[val, CD.Object], pair]
END;
pair^ ← [p, x, pair];
Enter[];
[] ← SymTab.Pairs[design.cellDirectory, EachCell];
FOR l: LIST OF CD.PushRec ← design.actual, l.rest WHILE l#NIL DO
MyEnum[l.first.dummyCell.ob, pair];
IF l.first.mightReplace#NIL THEN MyEnum[l.first.mightReplace.ob, pair];
ENDLOOP;
Leave[];
END;
BoundingBox: PUBLIC PROC [design: CD.Design]
RETURNS [r: CD.Rect ← CDBasics.empty] =
BEGIN
FOR l: LIST OF CD.PushRec ← design.actual, l.rest WHILE l#NIL DO
r ← CDBasics.Surround[r, CDInstances.BoundingRectO[
NARROW[l.first.dummyCell.ob.specificRef, CD.CellPtr].contents ]]
ENDLOOP;
END;
PushedCellName: PUBLIC PROC [design: CD.Design] RETURNS [Rope.ROPE] =
{RETURN [
IF design=NIL OR design.actual=NIL THEN "erronous"
ELSE IF design.actual.rest=NIL THEN "top level"
ELSE IF design.actual.first.specific=NIL THEN "erronous"
ELSE IF design.actual.first.specific.name#NIL THEN design.actual.first.specific.name
ELSE "unnamed cell" ]
};
RPEachChildren: CDDirectory.EnumerateObjectsProc --PROC [me: Object, x: REF]-- =
BEGIN
Process.Yield[];
IF ~me.class.inDirectory THEN
CDProperties.PutPropOnObject[onto: me, prop: x, val: NIL]
END;
RemoveProps: PROC [design: CD.Design, key: REF] =
BEGIN
RPEachDirectoryEntry: CDDirectory.EachEntryAction =
BEGIN
CDProperties.PutPropOnObject[onto: ob, prop: key, val: NIL];
IF ob.class.inDirectory THEN
CDDirectory.EnumerateChildObjects[me: ob, p: RPEachChildren, x: key];
END;
--RemoveProps
CedarProcess.SetPriority[CedarProcess.Priority[background]];
[] ← CDDirectory.Enumerate[design: design, action: RPEachDirectoryEntry];
END;
RemoveProperties: PUBLIC PROC [design: CD.Design, key: REF] =
--tries to remove the propertiy "key" from all objects of "design";
--may be delayed or incomplete
--(only from objects, not instances...)
BEGIN
TRUSTED {Process.Detach[FORK RemoveProps[design, key]]}
END;
ToLambda: PUBLIC PROC [n: CD.Number] RETURNS [Rope.ROPE] =
BEGIN
IF n MOD CD.lambda = 0 THEN
RETURN IO.PutFR[format: " %g", v1: IO.int[n/CD.lambda]]
ELSE {
r: Rope.ROPE ← " ";
IF n<0 THEN {
n ← ABS[n];
r ← " -";
};
RETURN [IO.PutFR["%0g(%0g+%0g/%0g)",
IO.rope[r], IO.int[n/CD.lambda], IO.int[n MOD CD.lambda], IO.int[CD.lambda]
]];
}
END;
PopToTopLayer: PUBLIC PROC [design: CD.Design] =
--if "design" is pushed in, it will be popped out, either by flushing,
--replacing cells or creating new cells
BEGIN
WHILE design.actual.rest#NIL DO
IF NOT CDCells.PopFromCell[design, newcell] THEN EXIT
ENDLOOP;
IF design.actual.rest#NIL THEN ERROR
END;
Cellize: PUBLIC PROC [design: CD.Design, name: Rope.ROPENIL] RETURNS [cell: CD.Object←NIL, pos: CD.Position] =
--makes a single "cell" of of the "design", removes all instances;
--pos: if "cell" is included at position "pos" in an empty design we would get "design" again
--if "design" is pushed in, it will be popped out, either by flushing,
--replacing cells or creating new cells
BEGIN
done: BOOL;
il: CD.InstanceList;
PopToTopLayer[design];
CDSimpleOps.SelectAll[design];
IF (il�Ops.InstList[design])#NIL THEN {
IF il.rest=NIL AND ISTYPE[il.first.ob.specificRef, CD.CellPtr] AND il.first.orientation=CD.original THEN {
cell ← il.first.ob;
IF name#NIL THEN [] ← CDDirectory.Rename[design, cell, name];
done ← TRUE
}
ELSE {
IF name=NIL THEN name ← design.name;
IF name=NIL THEN name ← "no named design";
[done, cell] ← CDCells.CreateCellSelected[design, name];
};
IF done THEN {
pos ← CDOps.InstList[design].first.location;
}
ELSE cell ← NIL
};
CDOps.SetInstList[design, NIL]
END;
RopeNeeded: SIGNAL [ ref: REF REF ] = CODE;
ToRope: PUBLIC PROC [x: REF, whenFailed: REFNIL] RETURNS [rope: Rope.ROPE←NIL] =
BEGIN
WITH x SELECT FROM
r: Rope.ROPE => rope ← r;
rt: REF TEXT => rope ← Rope.FromRefText[rt];
i: REF INT => rope ← IO.PutFR["%0g", IO.int[i^]];
a: ATOM => rope ← Atom.GetPName[a];
l: CDPrivate.LayerRef => rope ← CDOps.LayerName[l.number];
ob: CD.Object => rope ← CDOps.Info[ob];
inst: CD.Instance => rope ← inst.ob.class.describeInst[inst];
d: CD.Design => rope ← d.name;
t: CD.Technology => rope ← t.name;
ENDCASE =>
SELECT whenFailed FROM
NIL => rope ← NIL;
$Interactive => {
refRef: REF REF = NEW[REF ← x];
TerminalIO.WriteRope["please enter a ROPE using the debugger"];
SIGNAL RopeNeeded[refRef];
rope ← ToRope[refRef^ ! RopeNeeded => ERROR];
};
ENDCASE => rope ← ToRope[whenFailed];
END;
GetTechnology: PUBLIC PROC [name: Rope.ROPE] RETURNS [t: CD.Technology] =
--far more friendly version of CD.GetTechnology
--NIL if not found
BEGIN
EachTechnology: CD.TechnologyEnumerator = {
IF Rope.Equal[tech.name, name, FALSE]
OR Rope.Equal[Atom.GetPName[tech.key], name, FALSE]
THEN {quit ← TRUE; t ← tech}
};
[] ← CD.EnumerateTechnologies[EachTechnology];
END;
END.