PipalUIImpl.mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Louis Monier January 18, 1988 10:05:47 am PST
Bertrand Serlet May 16, 1988 0:00:03 am PDT
DIRECTORY
CD, CDBasics, CDCells, CDCellsInteractions, CDDefaultProcs, CDDirectory, CDEnvironment, CDImports, CDInstances, CDOps, CDSatellites, CDSequencer, CDSequencerExtras, CDViewer, CDViewHighlight,
IO, List,
Pipal, PipalCD, PipalInt, PipalIO, PipalMos, PipalOps, PipalUI,
PW, RefTab, Rope, SymTab, TerminalIO, ViewerClasses, ViewerOps;
PipalUIImpl:
CEDAR
PROGRAM
IMPORTS CD, CDBasics, CDCells, CDCellsInteractions, CDDefaultProcs, CDDirectory, CDEnvironment, CDImports, CDInstances, CDOps, CDSatellites, CDSequencerExtras, CDViewer, CDViewHighlight, IO, List, Pipal, PipalCD, PipalInt, PipalIO, PipalMos, PipalOps, PW, RefTab, Rope, SymTab, TerminalIO, ViewerOps
EXPORTS PipalUI
SHARES CDImports =
BEGIN OPEN PipalUI;
Preamble
ROPE: TYPE = Rope.ROPE;
Design
stupidCDProps: LIST OF REF ← LIST [$GeneratorProc, $CDxDrawSymbolics, $layerOfPin, $CDSatellitesGroupId, $CDBringoverLibraryName, $CDSatellitesOGroup, $OwnerDesign, $SatellitesCounter, $FileVersion, $CDSatellitesMax, $WireIconsConvertedFrom23, $FiddleKey];
otherProps:
LIST
OF
REF ←
LIST [$X, $PinOrder, $InstanceName, $DontFlatten, $Export, $MintDiscardMe];
UnknownProp:
SIGNAL [key:
ATOM, val:
REF] =
CODE;
DesignRoot:
PUBLIC
PROC [design: Design]
RETURNS [root: Pipal.Object] = {
Each: CDDirectory.EachEntryAction = {
[] ← SymTab.Store[directory, name, PipalCD.CDToPObject[ob]];
};
top: Pipal.Object ← PipalCD.CDToPObject[CDOps.RealTopCell[design]];
satellites: Pipal.Objects ← NIL;
directory: SymTab.Ref ← SymTab.Create[];
FOR props:
CD.PropList ← design.properties^, props.rest
WHILE props#
NIL
DO
key: REF ← props.first.key;
val: REF ← props.first.val;
IF
ISTYPE [key,
ATOM]
THEN
SELECT
TRUE
FROM
List.Memb[key, stupidCDProps] => {};
List.Memb[key, otherProps] =>
top ← Pipal.CreateAnnotation[top, NARROW [key], val];
ENDCASE => {
SIGNAL UnknownProp[NARROW [key], val];
otherProps← CONS [key, otherProps];
};
ENDLOOP;
FOR list:
CD.InstanceList ← CDSatellites.GetSatellites[design], list.rest
WHILE list#
NIL
DO
satellites ← CONS [PipalCD.CDToPInstance[list.first], satellites];
ENDLOOP;
[] ← CDDirectory.Enumerate[design, Each];
root ← Convert[PipalIO.CreateDirectory[design.name, PipalMos.CreateStar[top, satellites], directory], RefTab.Create[]];
};
Highlight and Viewer
highlightClass:
CD.ObjectClass ←
PW.RegisterClass[
objectType: $PipalHighlight,
expand: ExpandHighlight,
interestRect: CDDefaultProcs.InterestRect,
drawMe: HighlightDrawMe,
quickDrawMe: HighlightDrawMe,
showMeSelected: CDDefaultProcs.ShowMeSelected
];
Specific REF contains a CD.Object needing to be drawn highlighted.
ExpandHighlight: CDDirectory.ExpandProc = {
ERROR};
HighlightDrawMe:
CD.DrawProc = {
pr ← NEW [CD.DrawInformation ← pr^];
pr.drawRect ← HighlightDrawRect;
pr.drawChild[pr, NARROW [ob.specific], trans];
};
HighlightDrawRect:
CD.DrawRectProc = {
CDDefaultProcs.DrawRect[pr, r, CD.shadeLayer];
};
CreateHighlight:
PROC [cdobj:
CD.Object]
RETURNS [ob:
CD.Object] = {
ob ←
NEW [
CD.ObjectRep ← [
bbox: cdobj.bbox, class: highlightClass, immutable: TRUE, specific: cdobj
]];
};
HighlightDesign:
PUBLIC
PROC [design: Design, transformation: PipalInt.Transformation ← [], object: Pipal.Object ←
NIL, viewer: ViewerClasses.Viewer ←
NIL, label:
ROPE ←
NIL, rescale:
BOOL ←
TRUE] = {
bbox: CD.Rect;
cdhighlight: CD.Instance;
IF viewer=NIL THEN viewer ← FindViewer[design, label];
IF object=
NIL
THEN {
CDViewHighlight.ShowInstance[v: viewer, instOrList: NIL];
RETURN;
};
cdhighlight ← CDInstances.NewInst[
CreateHighlight[PipalCD.PToCDObject[object].cdobj],
PipalCD.PToCDTrans[transformation]
];
bbox ← CDInstances.InstRectO[cdhighlight];
CDViewHighlight.ShowInstance[v: viewer, instOrList: cdhighlight];
ViewerOps.OpenIcon[viewer];
IF NOT CDBasics.NonEmpty[bbox] THEN RETURN;
IF CDBasics.NonEmpty[bbox] AND rescale THEN CDViewer.ShowAndScale[viewer, bbox];
CDOps.ImmediateRedraw[design, bbox, FALSE];
};
FindViewer:
PUBLIC
PROC [design: Design, label:
ROPE ←
NIL]
RETURNS [viewer: ViewerClasses.Viewer] = {
viewer ← CDViewer.LastViewer[];
IF CDViewer.DesignOf[viewer]#design
THEN {
viewers: CDViewer.ViewerList ← CDViewer.ViewersOf[design];
IF viewers=
NIL
THEN {
viewer ← CDViewer.CreateViewer[design];
IF label#NIL THEN ViewerOps.SetViewer[viewer: viewer, data: label, op: $Label];
}
ELSE viewer ← viewers.first;
};
};
Selection
EnumerateSelectedObjects:
PUBLIC
PROC [design: Design, each: EachSelectedProc]
RETURNS [quit:
BOOL ←
FALSE] = {
pushPath: PipalOps.Path;
ThisInstance: CDCells.InstEnumerator = {
path: PipalOps.Path; trans: PipalInt.Transformation; child: Pipal.Object;
subPath: PipalOps.Path; found: BOOL;
cdtrans: CD.Transformation;
IF NOT inst.selected THEN RETURN;
IF design.actual.first.mightReplace=
NIL
THEN cdtrans ← inst.trans ELSE {
cdaux: CD.Transformation ← design.actual.first.mightReplace.trans;
cdtrans ← [
CDBasics.DeMapPoint[inst.trans.off, cdaux],
CDBasics.DecomposeOrient[itemInWorld: inst.trans.orient, cellInWorld: cdaux.orient]
];
};
trans ← PipalCD.CDToPTrans[cdtrans]; child ← PipalCD.CDToPObject[inst.ob];
[subPath, found] ← PipalOps.FindIntPath[
[], pushed, -- We do not deal here with pushed cell path WRONG
trans, child
];
IF NOT found THEN ERROR;
path ← PipalOps.ConcatPath[pushPath, subPath];
quit ← each[path, trans, child]
};
pushed: Pipal.Object ← PipalCD.CDToPObject[CDOps.PushedTopCell[design]];
IF pushed=Pipal.void THEN RETURN;
-- We do not deal here with pushed cell path WRONG
pushPath ← PipalOps.ExtendPath[NIL, ops, 0];
quit ← CDCells.EnumerateInstances[CDOps.PushedTopCell[design], ThisInstance];
};
TheSelectedObject:
PUBLIC
PROC [design: Design]
RETURNS [thePath: PipalOps.Path, theTrans: PipalInt.Transformation, theChild: Pipal.Object ←
NIL] = {
Each: EachSelectedProc = {
IF theChild=NIL THEN {thePath ← path; theTrans ← trans; theChild ← child} ELSE quit ← TRUE;
};
IF EnumerateSelectedObjects[design, Each] THEN theChild ← NIL;
IF theChild=NIL THEN TerminalIO.PutF["*** Several selected objects: cannot do it.\n"];
};
SelectInstance: PUBLIC PROC [design: Design, transformation: PipalInt.Transformation, object: Pipal.Object] RETURNS [done: BOOL] = {
FOR worldInstances: CD.InstanceList ← design.actual.first.specific.contents, worldInstances.rest UNTIL worldInstances=NIL DO
worldInstance: CD.Instance ← worldInstances.first;
IF SameInstances[
PipalCD.CDToPTrans[worldInstance.trans], PipalCD.CDToPObject[worldInstance.ob],
transformation, object
] THEN {worldInstance.selected ← TRUE; done ← TRUE; EXIT};
REPEAT FINISHED => done ← FALSE;
ENDLOOP;
};
Push
PushInstance: PUBLIC PROC [design: Design, transformation: PipalInt.Transformation, object: Pipal.Object] RETURNS [done: BOOL] = {
FOR worldInstances: CD.InstanceList ← design.actual.first.specific.contents, worldInstances.rest UNTIL worldInstances=NIL DO
worldInstance: CD.Instance ← worldInstances.first;
IF SameInstances[
PipalCD.CDToPTrans[worldInstance.trans], PipalCD.CDToPObject[worldInstance.ob],
transformation, object
] THEN {done ← CDCellsInteractions.PushInCellInstance[design, worldInstance]; EXIT};
REPEAT FINISHED => done ← FALSE;
ENDLOOP;
};
Replacement
ReplaceInDesign:
PUBLIC
PROC [design: Design, path: PipalOps.Path, table: PipalOps.ReplaceTable, replaceMethod: ReplaceMethod] = {
For now, we suppose the root is just design. Of course, this is bogus!
root: Pipal.Object ← DesignRoot[design];
SELECT replaceMethod
FROM
all => PipalOps.TransitiveReplace[root, table];
alongPath => PipalOps.ReplaceInPathWithTable[root, path, table];
ENDCASE => {
-- Wrong of course!
PipalOps.TransitiveReplace[root, table];
};
};
Command Registration
CommandTarget: TYPE = {any, theSelection, eachSelection};
CommandData: TYPE = REF CommandDataRec;
CommandDataRec:
TYPE =
RECORD [
target: CommandTarget,
refProc: REF,
replaceMethod: ReplaceMethod ← all, -- only valid for replacements
data: REF
];
cdCommandData: RefTab.Ref ← RefTab.Create[]; -- maps keys to registration data
CDCommandDispatcher:
PROC [comm: CDSequencer.Command] = {
design: Design = comm.design;
commandData: CommandData ← NARROW [RefTab.Fetch[cdCommandData, comm.key].val];
IF commandData=NIL THEN ERROR; -- command not registered!
WITH commandData.refProc
SELECT
FROM
refCommandProc:
REF CommandProc => {
IF commandData.target#any THEN ERROR;
refCommandProc^[
design, [comm.pos.x, comm.pos.y], [comm.sPos.x, comm.sPos.y],
commandData.data, comm.ref
];
};
refReplaceCommandProc:
REF ReplaceCommandProc => {
table: PipalOps.ReplaceTable ← RefTab.Create[];
SELECT commandData.target
FROM
theSelection => {
thePath: PipalOps.Path; theTrans: PipalInt.Transformation; theChild: Pipal.Object ← NIL;
[thePath, theTrans, theChild] ← TheSelectedObject[design];
refReplaceCommandProc^[design, theChild, table, commandData.data, comm.ref];
ReplaceInDesign[design, thePath, table, commandData.replaceMethod];
};
eachSelection => {
Each: EachSelectedProc = {
refReplaceCommandProc^[design, child, table, commandData.data, comm.ref];
ReplaceInDesign[design, path, table, commandData.replaceMethod];
};
[] ← EnumerateSelectedObjects[design, Each];
};
ENDCASE => ERROR;
};
ENDCASE => ERROR;
};
RegisterCommand:
PUBLIC
PROC [key:
ATOM, proc: CommandProc, queue, markChanged:
BOOL ←
TRUE, data:
REF ←
NIL] = {
commandData: CommandData ←
NEW [CommandDataRec ← [
target: any, refProc: NEW [CommandProc ← proc], data: data
]];
CDSequencerExtras.RegisterCommand[key, CDCommandDispatcher, NIL, IF queue THEN IF markChanged THEN doQueueAndMark ELSE doQueue ELSE IF markChanged THEN ERROR ELSE dontQueue];
[] ← RefTab.Store[cdCommandData, key, commandData];
};
RegisterReplaceSelectionCommand:
PUBLIC
PROC [key:
ATOM, proc: ReplaceCommandProc, allSelected:
BOOL, replaceMethod: ReplaceMethod, queue, markChanged:
BOOL ←
TRUE, data:
REF ←
NIL] = {
commandData: CommandData ←
NEW [CommandDataRec ← [
target: IF allSelected THEN eachSelection ELSE theSelection,
refProc: NEW [ReplaceCommandProc ← proc], replaceMethod: replaceMethod, data: data
]];
CDSequencerExtras.RegisterCommand[key, CDCommandDispatcher, NIL, IF queue THEN IF markChanged THEN doQueueAndMark ELSE doQueue ELSE IF markChanged THEN ERROR ELSE dontQueue];
[] ← RefTab.Store[cdCommandData, key, commandData];
};
Object Comparisons
Contains:
PUBLIC
PROC [object: Pipal.Object, candidateTrans: PipalInt.Transformation, candidateObject: Pipal.Object]
RETURNS [
BOOL] = {
ContainsChild: PipalInt.EachChildProc = {
IF transformation=candidateTrans AND child=candidateObject THEN RETURN [TRUE];
IF NOT PipalInt.IsInsideRectangle[PipalInt.BBox[child, transformation], PipalInt.BBox[candidateObject, candidateTrans]] THEN RETURN [FALSE];
quit ← PipalInt.HasEnumerate[child] AND PipalInt.Enumerate[child, ContainsChild, transformation];
};
SubCandidateNotContained: PipalInt.EachChildProc = {
quit ← NOT Contains[object, transformation, child];
};
IF ContainsChild[[], object] THEN RETURN [TRUE];
IF NOT PipalInt.HasEnumerate[candidateObject] THEN RETURN [FALSE];
RETURN [NOT PipalInt.Enumerate[candidateObject, SubCandidateNotContained, candidateTrans]];
};
SameInstances:
PUBLIC
PROC [trans1: PipalInt.Transformation, object1: Pipal.Object, trans2: PipalInt.Transformation, object2: Pipal.Object]
RETURNS [
BOOL] = {
RETURN [Contains[PipalInt.TransformObject[trans1, object1], trans2, object2] AND Contains[PipalInt.TransformObject[trans2, object2], trans1, object1]];
};
Junk Yard
GetTopInstances:
PUBLIC
PROC [design: Design]
RETURNS [topInstances: TopInstanceLists ←
NIL] = {
GetInstances:
PROC [design: Design] = {
thisTops: Pipal.Objects ← NIL;
stack: LIST OF CD.PushRec ← NIL;
trail: LIST OF CD.PushRec ← NIL;
FOR stack ← design.actual, stack.rest
UNTIL stack.rest=
NIL
DO
trail ← stack;
ENDLOOP;
thisTops ← LIST [PipalCD.CDToPObject[stack.first.dummyCell.ob]]; -- old code used to be slightly different here! (BS)
IF trail#NIL THEN thisTops ← CONS [PipalCD.CDToPInstance[trail.first.mightReplace], thisTops];
FOR cl:
LIST
OF CDImports.Cache ← CDImports.GetCacheList[design].list, cl.rest
UNTIL cl=
NIL
DO
IF RefTab.Insert[processedDesigns, cl.first.importee, $Done] THEN GetInstances[cl.first.importee];
ENDLOOP;
topInstances ← CONS[[design, thisTops], topInstances];
};
processedDesigns: RefTab.Ref ← RefTab.Create[];
GetInstances[design];
};
Random
schematicLambda: PUBLIC INT ← CD.FetchTechnology[$cmosB].lambda;
schematicFudge:
PUBLIC
INT ← schematicLambda / 2;
FetchKeyLine:
PUBLIC
PROC [fileName, key:
ROPE]
RETURNS [entry:
ROPE ←
NIL] = {
entry ← CDEnvironment.FetchKeyLine[fileName, key];
};
ExecuteInTerminal:
PUBLIC
PROC [entry:
ROPE] = {
[] ← CDEnvironment.StuffToCommandTool[entry];
};
Debug
Draw:
PUBLIC
PROC [object: Pipal.Object]
RETURNS [design: Design] = {
design ← PW.Draw[PipalCD.PToCDObject[object].cdobj];
};
Convertion code
TranslateCedarExpressionToScheme:
PROC [in:
ROPE]
RETURNS [out:
ROPE] = {
SELECT
TRUE
FROM
Rope.Match[" CoreOps.CreateWire[]", in] => RETURN ["(createwire)"];
Rope.Match["CoreClasses.CreateTransistor[nE, l, w]", in] => RETURN ["(createtransistor 'ne l w)"];
Rope.Match["CoreClasses.CreateTransistor[pE, l, w]", in] => RETURN ["(createtransistor 'pe l w)"];
Rope.Match["*[*", in] => {
TerminalIO.PutF["*** PipalCDImpl.TranslateCedarToScheme: not translated: '%g'.\n", IO.rope[in]];
RETURN [out];
};
ENDCASE => RETURN [out];
};
MatchProc: TYPE = PROC [old: ROPE] RETURNS [BOOL];
MatchTransistor: MatchProc = {RETURN [Rope.Match["*CreateTransistor[[*", old]]};
MatchAmpersand: MatchProc = {RETURN [Rope.Match["*&*←*", old]]};
MatchName: MatchProc = {RETURN [Rope.Match["name ← \"*\"", old]]};
MatchSchCI: MatchProc = {RETURN [Rope.Match["*cI*←*ES[\"*\",*cx]", old]]};
MatchCodeCI: MatchProc = {RETURN [Rope.Match["*cI*←*", old]]};
MatchCodeWI: MatchProc = {RETURN [Rope.Match["*wI*←*", old]]};
MatchWire: MatchProc = {RETURN [Rope.Match["*wire*←*", old]]};
MatchDeclare: MatchProc = {
RETURN [Rope.Match[ "*Sisyph.Store[cx,*\"*\",*NEW[*←*]]", old]]};
Change: PROC [master: REF, location: ROPE] RETURNS [needInteraction: ROPE ← NIL] = {
news: ROPES;
FOR list: ROPES ← NARROW [CDProperties.GetProp[master, Sisyph.expressionsProp]], list.rest WHILE list#NIL DO
old: ROPE = list.first;
SELECT TRUE FROM
MatchName[old] => {
new: ROPE = Rope.Substr[old, 8, Rope.Length[old]-9];
TerminalIO.PutF["changed '%g' to '%g'.\n", IO.rope[old], IO.rope[new]];
news ← CONS [new, news];
};
MatchSchCI[old] => {
pos1: INT ← Rope.Find[old, "\""];
pos2: INT ← Rope.Find[old, "\"", pos1+1];
sch: ROPE = Rope.Substr[old, pos1+1, pos2-pos1-1];
TerminalIO.PutF["changed '%g' to an $IconFor property '%g'.\n", IO.rope[old], IO.rope[sch]];
CDProperties.PutProp[master, $IconFor, sch];
CDProperties.PutProp[master, Sisyph.mode.extractProcProp, $SisyphExtractCellIcon]};
MatchCodeCI[old] => {
code: ROPE = Rope.Substr[old, Rope.Find[old, "←"]+1];
TerminalIO.PutF["changed '%g' to an $CodeFor property '%g'.\n", IO.rope[old], IO.rope[code]];
CDProperties.PutProp[master, $IconFor, NIL]; -- because $IconFor was not the truth in CD24!
CDProperties.PutProp[master, $CodeFor, code];
CDProperties.PutProp[master, Sisyph.mode.extractProcProp, $SisyphExtractCellIcon]};
MatchCodeWI[old] => {
code: ROPE = Rope.Substr[old, Rope.Find[old, "←"]+1];
TerminalIO.PutF["changed '%g' to an $CodeFor property '%g'.\n", IO.rope[old], IO.rope[code]];
CDProperties.PutProp[master, $CodeFor, code];
CDProperties.PutProp[master, Sisyph.mode.extractProcProp, $SisyphExtractNamedWireIcon]};
MatchWire[old] OR MatchTransistor[old] => {
TerminalIO.PutF["*** Found expression %g '%g' that is not converted automatically.\n", IO.rope[location], IO.rope[old]];
news ← CONS [old, news]};
MatchAmpersand[old] => {
TerminalIO.PutF["*** Found expression %g '%g' that uses a variable starting with '&'.\n", IO.rope[location], IO.rope[old]];
news ← CONS [old, news]};
MatchDeclare[old] => {
pos1: INT ← Rope.Find[old, "\""];
pos2: INT ← Rope.Find[old, "\"", pos1+1];
pos3: INT ← Rope.Find[old, "←", pos2+1];
pos4: INT ← Rope.Find[old, "]", pos3+1];
new: ROPE ← Rope.Cat[Rope.Substr[old, pos1+1, pos2-pos1-1], " ~ ", Rope.Substr[old, pos3+1, pos4-pos3-1]];
TerminalIO.PutF["changed '%g' to '%g'.\n", IO.rope[old], IO.rope[new]];
news ← CONS [new, news]};
ENDCASE => news ← CONS [old, news];
ENDLOOP;
CDProperties.PutProp[master, Sisyph.expressionsProp, news];
IF MatchTransistor[NARROW [CDProperties.GetProp[master, $CodeFor]]] THEN TerminalIO.PutF["*** Found $CodeFor %g '%g' that cannot be converted automatically.\n", IO.rope[location], IO.rope[NARROW [CDProperties.GetProp[master, $CodeFor]]]];
FOR list: ROPES ← CDSatellites.GetSatelliteRopes[master], list.rest WHILE list#NIL DO
old: ROPE = list.first;
SELECT TRUE FROM
MatchName[old] OR MatchSchCI[old] OR MatchCodeCI[old] OR MatchCodeWI[old] OR MatchWire[old] OR MatchDeclare[old] OR MatchTransistor[old] OR MatchAmpersand[old] => {
needInteraction ← Rope.Cat["'", old, "' ", needInteraction]};
ENDCASE => {};
ENDLOOP};
Convert:
PROC [old: Pipal.Object, table: PipalOps.ReplaceTable]
RETURNS [new: Pipal.Object] = {
new ← RefTab.Fetch[table, old].val;
IF new#NIL THEN RETURN;
WITH old
SELECT
FROM
icon: PipalMos.SchematicIcon => {
IF icon.code THEN new ← PipalMos.CreateSchematicIcon[Convert[icon.child, table], TranslateCedarExpressionToScheme[icon.expression], icon.code, icon.type];
};
annotation: Pipal.Annotation => {
SELECT annotation.key
FROM
ENDCASE => {};
};
ENDCASE => {};
IF new=
NIL
THEN {
PipalOps.TransitiveReplace[old, table];
new ← RefTab.Fetch[table, old].val;
};
IF new=NIL THEN new ← old;
[] ← RefTab.Store[table, old, new];
};
END.